flashman
← All posts

encodeURIComponent whole-URL debugging

Debug a link encoded as one string by separating encodeURIComponent from a full URL, and by reading the URI malformed error on a broken percent escape.

2026-10-18 · 6 min read · Rahul Chitturi

  • url
  • encoding
  • http

Flashman's URL tool runs encodeURIComponent on the whole box, or decodeURIComponent on the whole box. It does not call encodeURI, and it does not build a URL from parts. Encoding a complete address is a different operation from encoding one query value.

encodeURIComponent("https://flashman.dev/?q=hello world") prints https%3A%2F%2Fflashman.dev%2F%3Fq%3Dhello%20world. The scheme, the slashes, the question mark, and the equals sign are escaped. Pasting that result into a browser does not open the page. It is one component, which is what the function is specified to return.

Encode the value, then assemble the URL

hello world becomes hello%20world. a+b becomes a%2Bb, because a plus is a literal plus to this encoder, not a space. a b/c? becomes a%20b%2Fc%3F. café becomes caf%C3%A9, which is the UTF-8 bytes of é written as percent escapes. 100% becomes 100%25.

The characters left as themselves are letters, digits, and - _ . ! ~ * ' ( ). Everything else in a pasted URL, including :, /, ?, #, &, and =, is escaped. If the next system needs a navigable URL, encode only the segment or the query value, then put the reserved characters back yourself.

  • Keep https:// outside the encoder.
  • Encode a query value before you append it after =.
  • Expect a space to become %20, not +.
  • Expect a literal plus to become %2B.

Read a malformed escape before you decode twice

decodeURIComponent("hello%20world") is hello world. decodeURIComponent("hello+world") is hello+world: the plus is not turned into a space. A form body that used + for spaces needs a form decoder, not this box.

%, %2, and %zz each throw URI malformed, and the tool prints that message with an Error: prefix. A truncated escape is a broken input, not an empty result. already%20encoded encodes to already%2520encoded. Decoding that once returns already%20encoded, and decoding again returns the space. One accidental encode in front of a value that was already encoded is the usual source of %2520.

Diff the component you meant to send

Write the raw value, the encoded component, and the final URL on three lines. Diff the encoded component against what the server logged. If the log contains %253A, the scheme was encoded and then encoded again. If the log contains +, this tool was not the encoder that produced the space.

Use the URL tool on one component at a time, the JSON formatter when the component sits in a payload, and diff on the two encoded strings. Leave the reserved punctuation out of the box unless you are deliberately encoding it as data.

Try these tools