Guide
How to fix URIError: URI malformed in JavaScript
Find incomplete percent escapes, invalid UTF-8 bytes, and lone Unicode surrogates that cause URI malformed errors.
by Tools in a Tab · Published on · Reviewed on
Short answer
URIError: URI malformed usually has one of two causes. During decoding, a %
escape is incomplete or its bytes are not valid UTF-8. During encoding, the
JavaScript string contains a lone Unicode surrogate. Do not hide the exception
with an empty try/catch; preserve the input, identify the operation, and fix
the layer that produced it.
Separate encoding from decoding first
decodeURIComponent and decodeURI consume %HH sequences. They fail on %,
%A, %GG, or byte sequences that do not form valid UTF-8. For example,
%E0%A4%A is truncated before the character can be completed.
encodeURIComponent and encodeURI consume Unicode text. They may fail when
the string contains half of a surrogate pair, which can happen after slicing a
UTF-16 string at an arbitrary index or receiving corrupted internal data.
The URL encoder and decoder separates component, complete URL, and form-value modes and reports errors without sending the input elsewhere.
Incomplete percent escapes
Every % must be followed by exactly two hexadecimal digits. %20 is a space
and %2F represents /; %2, %XZ, and a final % are invalid. Inspect the
original before replacing % with %25, because that operation can turn
broken input into the literal text of a broken escape rather than restore the
intended value.
A common example interpolates a human percentage such as 50% into a URL and
later tries to decode it. When it belongs to a value, encode it as 50%25 at
the boundary where that component is constructed.
Invalid UTF-8 byte sequences
Escapes can contain valid hexadecimal pairs and still be invalid together.
decodeURIComponent('%C3%28') fails because C3 begins a two-byte UTF-8
sequence but 28 is not a continuation byte. Do not map each %HH directly to
a Latin-1 character. Assemble the bytes and decode them as strict UTF-8.
MDN describes both forms in its URI malformed error reference. The actual repair often belongs in the producer that truncated the data or used a different character encoding.
Lone Unicode surrogates during encoding
JavaScript strings contain UTF-16 code units. Many characters outside the
basic plane, including emoji, require a high and low surrogate. Cutting between
them leaves a lone unit that represents no valid Unicode scalar value, so
encodeURI may throw URIError.
Avoid truncating text by raw code units when character boundaries matter.
Array.from(text) or for…of iterates by code point, although complex visible
symbols can still require grapheme segmentation. On supported runtimes,
text.isWellFormed() can detect lone surrogates explicitly.
A debugging procedure
- Record safely whether the failure happened during encoding or decoding, without logging sensitive values.
- For decoding, locate the first
%not followed by two hexadecimal digits. - If escape syntax is complete, assemble the bytes and validate UTF-8.
- For encoding, verify that the Unicode string is well formed.
- Confirm whether the function should handle one component or a complete URL.
Do not repeatedly call decodeURIComponent until the string stops changing.
Every layer needs a documented reason, and a second pass can turn encoded data
into active delimiters.
Prevention
Keep values unencoded inside the application and encode them once at their
insertion boundary. Build addresses with URL and URLSearchParams, validate
external input before decoding, and test accents, emoji, %, truncated
escapes, and invalid byte sequences. A visible error is safer than continuing
with a URL whose meaning has silently changed.