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

  1. Record safely whether the failure happened during encoding or decoding, without logging sensitive values.
  2. For decoding, locate the first % not followed by two hexadecimal digits.
  3. If escape syntax is complete, assemble the bytes and validate UTF-8.
  4. For encoding, verify that the Unicode string is well formed.
  5. 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.