Common URL Encoding Errors and How to Fix Them
Diagnose and resolve the most frequent URL encoding mistakes in web applications and APIs.
How URL encoding works
URL encoding (percent-encoding) replaces characters that are not safe in a URL context with a % symbol followed by two hexadecimal digits representing the character's UTF-8 byte value. For example, a space becomes %20, and an ampersand becomes %26.
JavaScript provides two encoding functions: encodeURIComponent() encodes everything except unreserved characters (letters, digits, -, _, ., ~) and is used for individual values. encodeURI() additionally preserves URL structural characters like :/?#[]@!$&'()*+,;=and is used for complete URLs.
Error: malformed percent sequence
Symptom: Decoding fails with "URI malformed" or similar.
Cause: A lone % character or a % followed by non-hex characters (e.g. %GH, %2 ) is present in the string.
Fix: Scan the string for percent signs that are not followed by exactly two hex digits (0–9, A–F, a–f). Encode the literal % as %25 if it is not part of an escape sequence.
Error: query string breaks after encoding a full URL
Symptom: The encoded URL contains %3F and %3D where ?and = should be, making the query string unreadable to the server.
Cause: encodeURIComponent() was applied to the entire URL instead of individual parameter values. It escapes structural characters like ?, =, and &.
Fix: Use encodeURIComponent() only on individual query parameter values, not on the full URL. Use encodeURI() or the URL API for complete URLs.
Error: spaces appearing as + instead of %20
Symptom: After decoding, spaces are missing or appear as literal + characters.
Cause: HTML form submissions use application/x-www-form-urlencoded, which encodes spaces as + rather than %20. This is a legacy format not compliant with RFC 3986.
Fix: If you receive form data with + signs, replace them with spaces (or %20) before decoding. If you are generating encoded strings, use %20 for RFC 3986 compliance unless you specifically need HTML form encoding.
Error: double-encoding
Symptom: The decoded result still contains percent sequences like %2520(which is % encoded as %25, followed by 20).
Cause: The string was encoded twice. A value that was already encoded was encoded again, turning existing %20 sequences into %2520.
Fix: Decode the string once and inspect it. If the result still contains percent-encoded sequences, decode it again. To prevent this in code, only encode values at the last moment before assembling the URL — never encode something that may already be encoded.
Error: non-ASCII characters not encoded
Symptom: URLs with accented letters, emoji, or CJK characters cause 400 errors or corrupt data when sent to servers.
Cause: Non-ASCII characters were included in a URL without percent-encoding their UTF-8 byte sequences.
Fix: Always use encodeURIComponent() for any value that may contain non-ASCII characters. The function handles the UTF-8 conversion and percent-encoding in one step.
The boundary rule that prevents most bugs
The safest habit is to keep raw values raw inside your application and encode them only at the boundary where they become part of a URL. If values bounce between raw and encoded forms throughout the codebase, double-encoding and partial decoding are almost guaranteed eventually.
This is especially important in frontend apps that pass values through router helpers, analytics tags, and redirect logic. One premature encoding step can survive for months as a subtle bug.
A quick triage workflow
- Identify the URL context: full URL, path segment, query key, query value, or form body.
- Inspect the raw bytes or raw string before multiple helpers transform it further.
- Look for one extra encoding pass around redirects, API clients, or template interpolation.
- Test with spaces, ampersands, plus signs, and non-ASCII text because those reveal the bug fastest.