URL Encoder Double Encoding The Hidden Bug That Breaks Your Links
Double encoding turns %20 into %2520 and breaks URLs silently. Here's why it happens, how to spot it, and how to fix it before your users notice.
You share a link with a colleague: https://example.com/search?q=coffee+shop. They click it and get a 404. You check the URL in their browser and see %2520 where there should be a space. What happened? Double encoding — the URL got encoded twice, and now it's broken.
Double encoding is one of those bugs that's invisible in development, survives code review, and only appears when links pass through multiple systems. Here's how it happens and how to stop it.
How Double Encoding Happens
URL encoding converts special characters into %XX format. A space becomes %20. An ampersand becomes %26. The problem starts when a URL that's already encoded passes through a second encoder.
The second encoder sees the % character in %20 and thinks "this percent sign needs to be encoded too." So it encodes % as %25, turning %20 into %2520. Your browser now decodes %25 back to %, leaving you with the literal string %20 instead of a space.
This most commonly happens when: (1) your frontend encodes a query parameter, then your HTTP client encodes the entire URL again; (2) a redirect middleware re-encodes an already-encoded Location header; (3) you store encoded URLs in a database and encode them again on retrieval.
Spotting Double Encoding in the Wild
The telltale sign is %25 in your URL. If you see %2520, %2526, or %253D, you're looking at double encoding. %25 is the encoded version of %, so every double-encoded character starts with %25.
Quick diagnostic: decode the URL once. If the result still contains %XX sequences, decode it again. If the second decode produces readable text, you had double encoding. If the first decode already produces readable text, the URL was correctly single-encoded.
The Query String Is the Most Common Victim
Query strings are where double encoding does the most damage. A user searches for "café & bakery" and the URL should be ?q=caf%C3%A9+%26+bakery. If it gets double-encoded, %C3%A9 becomes %25C3%25A9 and your server receives gibberish.
This gets worse with multi-byte UTF-8 characters. Chinese, Arabic, and emoji characters produce multiple %XX sequences. Double-encoding a single Chinese character can produce 18+ characters of percent-encoded chaos.
Prevention: Encode Once, At the Boundary
The golden rule: encode at the last possible moment, when the URL leaves your system. Don't encode data before storing it in a database. Don't encode in your React state. Encode when you construct the final URL string that goes into an <a href> or fetch() call.
If you're building URLs programmatically, use the URL constructor or a URL-building library instead of string concatenation. new URL('/search', base).searchParams.set('q', query) handles encoding correctly and won't double-encode.
For encoding URLs safely, use our URL encoder which shows you exactly what gets encoded. For checking if a broken URL has been double-encoded, paste it into our text diff tool alongside the expected version. And for decoding URLs to see what they actually contain, decode in stages to spot the double-encoding layer.
Tools mentioned in this article
URL Encoder/Decoder
Encode special characters in URLs and decode percent-encoded strings back to normal text. Handles full URLs or individual components. Essential for working with query parameters and form data.
Text Diff Checker
Compare two pieces of text side by side and see exactly what changed. Highlights additions, deletions, and modifications. Drop in old and new versions to spot edits.
