HTML Guides for illegal character
Learn how to identify and fix common HTML validation errors flagged by the W3C Validator — so your pages are standards-compliant and render correctly across every browser. Also check our Accessibility Guides.
The W3C HTML Validator checks that URLs used in attributes like href conform to the URL Standard maintained by WHATWG. According to this standard, only certain characters are permitted to appear literally in the query component of a URL. The pipe character (|, Unicode U+007C) is not in the set of allowed query characters, which means it must be percent-encoded as %7C when it appears in a URL's query string.
While most modern browsers will silently handle a raw | in a URL and still navigate to the intended destination, relying on this behavior is problematic for several reasons:
- Standards compliance: HTML documents that contain unencoded special characters in URLs are technically invalid and will fail W3C validation.
- Interoperability: Not all user agents, HTTP clients, web scrapers, or proxy servers handle illegal URL characters the same way. An unencoded pipe could be misinterpreted, stripped, or cause unexpected behavior in certain environments.
- Security: Properly encoding URLs helps prevent injection attacks and ensures that each part of the URL is unambiguously parsed. Unencoded special characters can be exploited in certain contexts.
- Link sharing and processing: URLs are often copied, pasted, embedded in emails, or processed by APIs. An unencoded
|may break the URL when it passes through systems that strictly enforce URL syntax.
This issue commonly arises when URLs are constructed by hand, pulled from databases, or generated by backend systems that don't automatically encode query parameters. It can also appear when using pipe-delimited values as query parameter values (e.g., ?filter=red|blue|green).
The fix is straightforward: replace every literal | in the URL with its percent-encoded equivalent %7C. If you're generating URLs in code, use built-in encoding functions like JavaScript's encodeURIComponent() or PHP's urlencode() to handle this automatically.
Examples
Incorrect: raw pipe character in query string
<ahref="https://example.com/search?q=test|demo">Search</a>
The literal | in the query string triggers the validation error.
Correct: pipe character percent-encoded
<ahref="https://example.com/search?q=test%7Cdemo">Search</a>
Replacing | with %7C makes the URL valid. The server receiving this request will decode it back to test|demo automatically.
Incorrect: multiple pipe characters as delimiters
<ahref="https://example.com/filter?colors=red|blue|green">Filter colors</a>
Correct: all pipe characters encoded
<ahref="https://example.com/filter?colors=red%7Cblue%7Cgreen">Filter colors</a>
Generating encoded URLs in JavaScript
If you're building URLs dynamically, use encodeURIComponent() to encode individual parameter values:
<script>
constcolors="red|blue|green";
consturl="https://example.com/filter?colors="+encodeURIComponent(colors);
// Result: "https://example.com/filter?colors=red%7Cblue%7Cgreen"
</script>
This ensures that any special characters in the value — including |, spaces, ampersands, and others — are properly encoded without you needing to remember each character's percent-encoded form.
Other characters to watch for
The pipe character is not the only one that causes this validation error. Other characters that must be percent-encoded in URL query strings include curly braces ({ and }), the caret (^), backtick (`), and square brackets ([ and ]) when used outside of specific contexts. As a general rule, always encode user-supplied or dynamic values using your language's URL encoding function rather than constructing query strings through simple string concatenation.
A link element's href attribute contains a character that is not valid in a URL, such as a space, curly brace, or other unencoded special character.
URLs in HTML must conform to the URL Living Standard. Certain characters are not allowed to appear literally in a URL and must be percent-encoded. Common offenders include spaces (use %20), curly braces { } (use %7B %7D), pipe | (use %7C), and angle brackets < > (use %3C %3E).
This error often appears when a template placeholder like {{variable}} is left unresolved in the href value, or when a URL is copied from another context and contains unencoded characters. The validator reads the raw HTML source, so even if a browser might handle a malformed URL gracefully, the markup is still invalid.
To fix it, replace every illegal character with its percent-encoded equivalent, or remove the character if it does not belong in the URL.
Examples
Invalid: unencoded characters in href
<linkrel="stylesheet"href="https://example.com/styles/main file.css">
The space between main and file is not allowed in a URL.
Valid: percent-encoded URL
<linkrel="stylesheet"href="https://example.com/styles/main%20file.css">
If the illegal characters come from a template placeholder that was never processed, remove the placeholder or ensure it resolves before the HTML is served:
Invalid: unresolved template syntax
<linkrel="icon"href="https://example.com/{{icon_path}}">
Valid: resolved or corrected URL
<linkrel="icon"href="https://example.com/images/favicon.ico">
The URL standard defines a specific set of characters that are allowed to appear literally in a URL's query string. Characters outside this allowed set — such as |, [, ], {, }, ^, and unencoded spaces — must be percent-encoded. Percent-encoding replaces the character with a % sign followed by its two-digit hexadecimal ASCII code.
This matters for several reasons. Browsers may handle illegal characters inconsistently — some might silently fix them while others may not, leading to broken links. Screen readers and assistive technologies rely on well-formed URLs to properly announce link destinations. Search engine crawlers may also fail to follow URLs with illegal characters, which can hurt discoverability. Using properly encoded URLs ensures your links work reliably across all user agents and conform to both the HTML and URL specifications.
Common Characters That Need Encoding
Here are frequently encountered characters that trigger this validation error:
| Character | Percent-Encoded |
|---|---|
| (space) | %20 (or + in query strings) |
| | %7C |
[ | %5B |
] | %5D |
{ | %7B |
} | %7D |
^ | %5E |
Note that characters like ?, =, &, and # have special meaning in URLs and are allowed in their respective positions. For example, ? starts the query string, & separates parameters, and = separates keys from values. However, if these characters appear as part of a parameter's value (rather than as delimiters), they must also be percent-encoded.
How to Fix It
- Identify the illegal character mentioned in the validator's error message.
- Replace it with its percent-encoded equivalent.
- If you're generating URLs dynamically with a server-side language, use built-in encoding functions like
encodeURIComponent()in JavaScript,urlencode()in PHP, orurllib.parse.quote()in Python.
Examples
❌ Incorrect: Unencoded pipe character in query string
<ahref="https://example.com/search?filter=red|blue">Search</a>
✅ Correct: Pipe character percent-encoded as %7C
<ahref="https://example.com/search?filter=red%7Cblue">Search</a>
❌ Incorrect: Unencoded square brackets in query string
<ahref="https://example.com/api?items[0]=apple&items[1]=banana">View items</a>
✅ Correct: Square brackets percent-encoded
<ahref="https://example.com/api?items%5B0%5D=apple&items%5B1%5D=banana">View items</a>
❌ Incorrect: Unencoded space in query string
<ahref="https://example.com/search?q=hello world">Search</a>
✅ Correct: Space encoded as %20
<ahref="https://example.com/search?q=hello%20world">Search</a>
If you're building URLs in JavaScript, use encodeURIComponent() on individual parameter values rather than encoding the entire URL. This function handles all characters that need encoding while leaving the URL structure intact:
constquery="red|blue";
consturl=`https://example.com/search?filter=${encodeURIComponent(query)}`;
// Result: "https://example.com/search?filter=red%7Cblue"
Avoid using encodeURI() for this purpose, as it does not encode characters like [, ], or | that are illegal in query strings. Always use encodeURIComponent() for encoding individual query parameter names and values.
URLs must conform to the URL Living Standard, which forbids tab characters (U+0009) within the host/domain portion of a URL. While some browsers may silently strip tabs and still navigate to the intended destination, this behavior is not guaranteed and should not be relied upon.
This issue typically arises from one of the following scenarios:
- Copy-paste errors: Copying a URL from a document, email, or spreadsheet that inadvertently includes tab characters.
- Template or build tool formatting: A templating engine or code generator inserting whitespace (including tabs) into a URL string, especially when the URL is constructed across multiple lines.
- Manual typos: Accidentally pressing the Tab key while editing an
hrefvalue, particularly in editors that don't visualize whitespace.
Tab characters are invisible in most code editors by default, which makes this error frustrating to track down. Enabling "show whitespace" or "show invisible characters" in your editor can help you spot the offending character.
Why this matters
- Standards compliance: The HTML specification requires that
hrefvalues contain valid URLs. A tab in the domain makes the URL syntactically invalid. - Accessibility: Screen readers and assistive technologies parse
hrefvalues to announce link destinations. An invalid URL can lead to confusing or broken announcements. - Reliability: While major browsers tend to be forgiving and strip tabs before resolving URLs, some HTTP clients, crawlers, or older browsers may not. This can cause broken links in unexpected contexts like RSS readers, email clients, or web scrapers.
How to fix it
- Enable visible whitespace in your editor to locate tab characters.
- Search for tab characters in your
hrefvalues. In many editors, you can use a regex search for\twithin attribute values. - Remove the tab characters so the URL is a clean, continuous string with no embedded whitespace.
- If URLs are dynamically generated, inspect the code that builds them to ensure no tabs or other whitespace are concatenated into the domain.
Examples
❌ Incorrect: Tab character in the domain
In the example below, a tab character is embedded within the domain name (represented here as 	 for visibility, though in source code it would be an actual invisible tab):
<!-- The tab between "example" and ".com" causes the error -->
<ahref="https://example .com/page">Visit Example</a>
Note: The tab character between example and .com is invisible in most editors but triggers the validation error.
✅ Correct: Clean URL with no whitespace
<ahref="https://example.com/page">Visit Example</a>
❌ Incorrect: Tab introduced by multi-line URL construction in a template
This can happen when a URL is broken across lines in a template and tabs are used for indentation:
<ahref="https:// example.com/page">Visit Example</a>
example.com/page
✅ Correct: URL on a single line with no embedded whitespace
<ahref="https://example.com/page">Visit Example</a>
Tip: Finding hidden tabs
If you're having trouble locating the tab character, try pasting your href value into a tool that reveals character codes, or run a quick check in your browser's developer console:
// Check for tabs in a URL string
consturl=document.querySelector('a').getAttribute('href');
console.log(url.includes('\t'));// true if a tab is present
console.log(JSON.stringify(url));// shows \t explicitly in the output
URLs used in HTML attributes must follow the URL Living Standard, which defines a specific set of characters that are allowed in each part of a URL. The query component of a URL — everything after the ? — permits most printable ASCII characters, but certain characters are still considered illegal and must be percent-encoded. When the W3C validator encounters one of these forbidden characters in the href of a <link> element, it raises this error.
Common characters that trigger this issue include:
| Character | Percent-encoded |
|---|---|
| ` | ` (pipe) |
[ (left bracket) | %5B |
] (right bracket) | %5D |
{ (left brace) | %7B |
} (right brace) | %7D |
^ (caret) | %5E |
` (backtick) | %60 |
| (space) | %20 |
Why this matters
While many modern browsers are lenient and will silently fix malformed URLs, relying on this behavior is risky. Invalid URLs can cause problems in several ways:
- Inconsistent browser behavior: Not all user agents handle illegal characters the same way, which can lead to broken stylesheets or resources failing to load.
- Interoperability issues: Proxies, CDNs, and other intermediaries may reject or mangle URLs with illegal characters.
- Standards compliance: Valid HTML requires valid URLs in attributes. An illegal character in the
hrefmakes the entire document non-conforming. - Copy-paste and sharing reliability: Malformed URLs are more likely to break when shared across systems, emails, or documentation.
How to fix it
Identify the illegal characters in your URL's query string and replace each one with its percent-encoded equivalent. If you're generating URLs programmatically, use a proper URL encoding function (e.g., encodeURIComponent() in JavaScript, urlencode() in PHP, or urllib.parse.quote() in Python) to ensure all special characters are encoded correctly.
Examples
❌ Illegal pipe character in the query string
This is a common pattern seen with Google Fonts URLs that use | to separate font families:
<linkrel="stylesheet"href="https://fonts.googleapis.com/css?family=Open+Sans|Roboto">
✅ Pipe character percent-encoded
<linkrel="stylesheet"href="https://fonts.googleapis.com/css?family=Open+Sans%7CRoboto">
❌ Square brackets in the query string
Some APIs or frameworks use bracket notation in query parameters:
<linkrel="stylesheet"href="https://example.com/styles?themes[]=dark&themes[]=compact">
✅ Square brackets percent-encoded
<linkrel="stylesheet"href="https://example.com/styles?themes%5B%5D=dark&themes%5B%5D=compact">
❌ Space character in the query string
<linkrel="stylesheet"href="https://example.com/css?file=my styles.css">
✅ Space character percent-encoded
<linkrel="stylesheet"href="https://example.com/css?file=my%20styles.css">
Note that for Google Fonts specifically, the modern API (v2) uses a different URL format that avoids the pipe character altogether. Where possible, consider updating to the latest version of an API rather than just encoding the old URL.
URLs follow a strict syntax defined by the URL Living Standard and RFC 3986. Only a specific set of characters are allowed to appear literally in a URL's query string. Characters outside this set — such as pipes, square brackets, curly braces, and certain other symbols — must be percent-encoded. Percent-encoding replaces the character with a % sign followed by its two-digit hexadecimal ASCII code.
When the W3C HTML Validator encounters an <img> tag whose src attribute contains an illegal character in the query portion of the URL, it raises this error. The query string is the part of the URL that comes after the ? character.
Why this matters
- Browser inconsistency: While many modern browsers will silently fix malformed URLs, not all browsers or HTTP clients handle illegal characters the same way. Some may misinterpret the URL or fail to load the resource entirely.
- Standards compliance: Valid URLs are a foundational requirement for interoperable web content. Using illegal characters violates both the HTML and URL specifications.
- Interoperability: Automated tools, web crawlers, proxies, and content delivery networks may reject or mangle URLs containing unencoded special characters, leading to broken images.
- Accessibility: Screen readers and assistive technologies rely on valid markup. Malformed URLs can cause unexpected behavior in these tools.
Common illegal characters and their encodings
Here are characters frequently flagged by the validator:
| Character | Percent-encoded |
|---|---|
| (pipe) | %7C |
[ | %5B |
] | %5D |
{ | %7B |
} | %7D |
^ | %5E |
` (backtick) | %60 |
| (space) | %20 |
How to fix it
Identify the illegal characters in the src URL and replace each one with its corresponding percent-encoded value. If you're generating URLs dynamically with a programming language, use the language's built-in URL-encoding function (e.g., encodeURI() or encodeURIComponent() in JavaScript, urlencode() in PHP, urllib.parse.quote() in Python).
Examples
❌ Incorrect: unencoded pipe character in query string
<imgsrc="https://example.com/image?filter=red|blue"alt="Filtered image">
The | character is not allowed literally in the query string.
✅ Correct: pipe character percent-encoded
<imgsrc="https://example.com/image?filter=red%7Cblue"alt="Filtered image">
❌ Incorrect: unencoded square brackets in query string
<imgsrc="https://example.com/image?size[width]=300&size[height]=200"alt="Resized image">
The [ and ] characters must be encoded.
✅ Correct: square brackets percent-encoded
<imgsrc="https://example.com/image?size%5Bwidth%5D=300&size%5Bheight%5D=200"alt="Resized image">
❌ Incorrect: space in query string
<imgsrc="https://example.com/image?caption=hello world"alt="Captioned image">
✅ Correct: space percent-encoded
<imgsrc="https://example.com/image?caption=hello%20world"alt="Captioned image">
Encoding URLs dynamically
If your URLs are built in JavaScript, use encodeURIComponent() for individual query parameter values:
constfilter="red|blue";
consturl=`https://example.com/image?filter=${encodeURIComponent(filter)}`;
// Result: "https://example.com/image?filter=red%7Cblue"
This ensures that any special characters in user-provided or dynamic values are properly encoded before being placed into the HTML.
Validate at scale.
Ship accessible websites, faster.
Automated HTML & accessibility validation for large sites. Check thousands of pages against WCAG guidelines and W3C standards in minutes, not days.
Pro Trial
Full Pro access. Cancel anytime.
Start Pro Trial →Join teams across 40+ countries