ENES
url-encodingEngineering Guide

Why Your URL Parameters Break: Fixing Encoding Bugs with Spaces, +, and & (2026)

AC
Alex Chen·Lead Systems Architect
Published on 2026-08-30·9 min read·Daily Toolbox Engineering

Why Your URL Parameters Break: Fixing Encoding Bugs with Spaces, +, and & (2026)

You build a URL with a search query. It works for "hello" but breaks for "hello world" or "AT&T" or "C++". Your API returns 400 errors, redirects fail, or half your parameter vanishes.

URL encoding bugs are silent killers. They work in testing (simple inputs) then break in production (real user data with spaces, ampersands, and Unicode).

This guide shows you exactly which characters break URLs, why, and how to encode them correctly—including the notorious + vs %20 trap and double-encoding disasters.


Why URLs Break: Reserved Characters

The Problem in One Example

You want to search for: salt & pepper

Naive URL:

https://api.example.com/search?q=salt & pepper

What the server sees:

  • Parameter q = salt (truncated at the space!)
  • & pepper interpreted as a second parameter

Result: Your search for "salt & pepper" becomes a search for "salt".


Reserved Characters That MUST Be Encoded

These characters have special meaning in URLs. If they appear in data, they must be percent-encoded:

Character Meaning in URL Encoded As
space Separator %20 (or + in query)
& Parameter separator %26
= Key-value separator %3D
? Query start %3F
# Fragment start %23
/ Path separator %2F
+ Space (in query) %2B
% Escape character %25

The rule: If these appear in your data (not as structural URL parts), encode them.


The Infamous + vs %20 Trap

Two Ways to Encode a Space

This trips up even senior developers:

Context Space Encoded As Standard
Query string (?q=...) + OR %20 application/x-www-form-urlencoded
Path (/foo/...) %20 ONLY RFC 3986

The Bug This Causes

Scenario: You encode a space as + in a URL path:

https://example.com/files/my+document.pdf

Server interprets: Literal filename my+document.pdf (with a plus sign!)

Correct:

https://example.com/files/my%20document.pdf

The Reverse Bug

Scenario: User searches for C++ (the programming language):

https://example.com/search?q=C++

Server decodes: C (two spaces! because + = space in query strings)

Correct:

https://example.com/search?q=C%2B%2B

The fix: In query strings, always encode literal + as %2B.


JavaScript: encodeURI vs encodeURIComponent

The Critical Difference

JavaScript has two encoding functions, and using the wrong one is the #1 cause of URL bugs:

Function Encodes Use For
encodeURI() Spaces, Unicode — but NOT & = ? / # Encoding a whole URL
encodeURIComponent() Everything reserved, including & = ? / Encoding a single parameter value

When Each Fails

Using encodeURI for a parameter value (WRONG):

const query = "salt & pepper";
const url = "https://api.com/search?q=" + encodeURI(query);
// Result: ?q=salt%20&%20pepper  ← & NOT encoded, breaks!

Using encodeURIComponent (CORRECT):

const query = "salt & pepper";
const url = "https://api.com/search?q=" + encodeURIComponent(query);
// Result: ?q=salt%20%26%20pepper  ← & encoded as %26, works!

The Rule

  • Encoding one value (a parameter, a path segment)? → encodeURIComponent()
  • Encoding a complete URL you built yourself? → encodeURI()

99% of the time, you want encodeURIComponent().


Building URLs Correctly: URLSearchParams

Stop String-Concatenating URLs

The modern, bug-free way to build query strings:

const params = new URLSearchParams({
  q: "salt & pepper",
  category: "food/spices",
  price: "10+"
});

const url = "https://api.com/search?" + params.toString();
// Result: ?q=salt+%26+pepper&category=food%2Fspices&price=10%2B
// All special characters correctly encoded automatically

Why this is better:

  • Automatically encodes all values
  • Handles &, =, spaces, Unicode correctly
  • No manual encoding mistakes
  • Readable code

Reading Parameters Back

const url = new URL("https://api.com/search?q=salt+%26+pepper");
const q = url.searchParams.get("q");
// q = "salt & pepper"  ← automatically decoded

The Double-Encoding Disaster

How It Happens

Step 1: Frontend encodes a value:

encodeURIComponent("a&b")  // → "a%26b"

Step 2: Backend receives a%26b, encodes it AGAIN before storing/forwarding:

"a%26b" → "a%2526b"  (% became %25)

Step 3: When decoded once, you get a%26b instead of a&b. The value is corrupted.

How to Detect Double-Encoding

Look for %25 in your URLs where you didn't intend a literal %:

  • %2526 = double-encoded &
  • %2520 = double-encoded space
  • %253D = double-encoded =

The Fix

Encode exactly once. Establish clear ownership:

  • Frontend encodes when building the URL
  • Backend decodes on receipt, stores raw
  • Backend re-encodes only when forwarding to another URL

Never blindly encode data that might already be encoded.


Unicode and International Characters

The UTF-8 Percent-Encoding

Non-ASCII characters (emoji, accents, CJK) must be UTF-8 encoded, then percent-encoded:

Character UTF-8 Bytes URL Encoded
é 0xC3 0xA9 %C3%A9
中 0xE4 0xB8 0xAD %E4%B8%AD
😀 0xF0 0x9F 0x98 0x80 %F0%9F%98%80

JavaScript handles this automatically:

encodeURIComponent("café")     // → "caf%C3%A9"
encodeURIComponent("北京")      // → "%E5%8C%97%E4%BA%AC"
encodeURIComponent("hello 😀")  // → "hello%20%F0%9F%98%80"

Common Unicode Bug

Problem: Server expects Latin-1 but gets UTF-8, or vice versa. Result: café becomes café.

Fix: Ensure both ends use UTF-8. Set Content-Type: text/html; charset=utf-8 and use UTF-8 encoding functions consistently.


Real-World Debugging Checklist

When a URL parameter breaks, check in order:

☐ Is the value encoded at all? (spaces, & present raw?)
☐ Right function? (encodeURIComponent for values, not encodeURI)
☐ Plus sign issue? (literal + in query = space bug)
☐ Double-encoded? (look for %25 you didn't intend)
☐ Unicode charset? (UTF-8 both ends?)
☐ Path vs query? (spaces: %20 in path, + or %20 in query)


Encoding Reference: Copy-Paste Safe

Encode a single parameter value

const encoded = encodeURIComponent(value);

Build a full query string

const qs = new URLSearchParams({ key1: val1, key2: val2 }).toString();

Decode a value

const decoded = decodeURIComponent(encoded);

Python equivalent

from urllib.parse import quote, urlencode, unquote
quote("salt & pepper")           # 'salt%20%26%20pepper'
urlencode({"q": "salt & pepper"}) # 'q=salt+%26+pepper'
unquote("salt%20%26%20pepper")    # 'salt & pepper'

FAQ

Q: Should I use + or %20 for spaces?
A: In query strings, both work (+ is form-encoding standard). In paths, use %20 only. When in doubt, %20 works everywhere.

Q: Why does my + sign turn into a space?
A: In query strings, + means space. To send a literal +, encode it as %2B.

Q: encodeURI or encodeURIComponent?
A: encodeURIComponent for individual values (99% of cases). encodeURI only when encoding a complete, already-structured URL.

Q: How do I know if a URL is double-encoded?
A: Look for %25 (encoded %) where you expected a single-encoded character. %2520 = double-encoded space.

Q: Do I need to encode Unicode manually?
A: No. encodeURIComponent() (JS) and quote() (Python) handle UTF-8 encoding automatically.


Conclusion

URL encoding bugs come from a few predictable mistakes:

  1. Not encoding reserved characters (& = ? / in data)
  2. Wrong function (encodeURI vs encodeURIComponent)
  3. The + trap (literal + becomes space in queries)
  4. Double-encoding (encoding already-encoded data)
  5. Charset mismatch (not using UTF-8 consistently)

The safe defaults:

  • Use encodeURIComponent() for values
  • Use URLSearchParams to build query strings
  • Encode exactly once
  • UTF-8 everywhere

Follow these and your URLs will handle spaces, ampersands, plus signs, and 😀 without breaking.

#url-encoding#encodeuricomponent#query-parameters#percent-encoding
AC
Written by Alex ChenLead Architect

Alex Chen is a distributed systems engineer and core maintainer at Daily Toolbox with over 10 years of experience in client-side web technologies, RFC standards compliance, and cryptographic protocols. He specializes in zero-knowledge client architectures and WebAssembly-accelerated algorithms.

Try the free tools mentioned above

⚡ Open URL Encoder & Decoder →