HTML Guides for character reference
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.
A numeric character reference is pointing to a C1 control code point (U+0080–U+009F), which is disallowed in HTML.
Numeric character references like &#nnn; or hhhh; must resolve to valid Unicode characters.
The C1 control range U+0080–U+009F contains non-characters/control codes, so validators flag them.
Common causes: copying Windows-1252 bytes and encoding them as numeric references (e.g., — for an em dash) or misusing hex values (e.g., for a right single quote).
In HTML, use the proper Unicode character, a valid named character reference, or the correct Unicode code point. Examples: use the actual “—” or — (U+2014), “’” or ’ (U+2019), “€” or € (U+20AC). If you must use numeric references, use the correct code points: — or — for em dash, not —; ’ or ’ for right single quote, not .
HTML Examples
Example that reproduces the issue
<!doctype html>
<html lang="en">
<head>
<title>Bad C1 NCR</title>
</head>
<body>
<p>Bad dash: —</p>
<p>Bad quote: ’</p>
</body>
</html>
Fixed example
<!doctype html>
<html lang="en">
<head>
<title>Fixed NCRs</title>
</head>
<body>
<p>Good dash: — or — or —</p>
<p>Good quote: ’ or ’ or ’</p>
<p>Euro: € or € or €</p>
</body>
</html>
What Are Control Characters?
Control characters occupy code points U+0000 through U+001F and U+007F through U+009F in Unicode. They were originally designed for controlling hardware devices (e.g., U+0002 is “Start of Text,” U+0007 is “Bell,” U+001B is “Escape”). These characters have no visual representation and carry no semantic meaning in a web document.
The HTML specification explicitly forbids character references that resolve to most control characters. Even though the syntax  is a structurally valid character reference, the character it points to is not a permissible content character. The W3C validator raises this error to flag references like �, , , , and others that fall within the control character ranges.
Why This Is a Problem
- Standards compliance: The WHATWG HTML Living Standard defines a specific set of “noncharacter” and “control character” code points that must not be referenced. Using them produces a parse error.
- Unpredictable rendering: Browsers handle illegal control characters inconsistently. Some may silently discard them, others may render a replacement character (�), and others may exhibit unexpected behavior.
- Accessibility: Screen readers and other assistive technologies may choke on or misinterpret control characters, degrading the experience for users who rely on these tools.
- Data integrity: Control characters in your markup often indicate a copy-paste error, a corrupted data source, or a templating bug that inserts raw binary data into HTML output.
How to Fix It
- Identify the offending reference — look for character references like , , �, , or similar that point to control character code points.
- Determine intent — figure out what character or content was actually intended. Often, a control character reference is the result of a bug in a data pipeline or template engine.
- Remove or replace — either delete the reference entirely or replace it with the correct printable character or HTML entity.
Examples
Incorrect: Control character reference
This markup contains , which expands to the control character U+0002 (Start of Text) and triggers the validation error:
<p>Some text  more text</p>
Incorrect: Hexadecimal form of a control character
The same problem occurs with the hexadecimal syntax:
<p>Data: </p>
Correct: Remove the control character reference
If the control character was unintentional, simply remove it:
<p>Some text more text</p>
Correct: Use a valid character reference instead
If you intended to display a special character, use the correct printable code point or named entity. For example, to display a bullet (•), copyright sign (©), or ampersand (&):
<p>Item • Details</p>
<p>Copyright © 2024</p>
<p>Tom & Jerry</p>
Correct: Full document without control characters
<!DOCTYPE html>
<html lang="en">
<head>
<title>Example Page</title>
</head>
<body>
<p>This paragraph uses only valid character references: & < > ©</p>
</body>
</html>
Common Control Character Code Points to Avoid
| Reference | Code Point | Name |
|---|---|---|
| � | U+0000 | Null |
|  | U+0001 | Start of Heading |
|  | U+0002 | Start of Text |
|  | U+0007 | Bell |
|  | U+0008 | Backspace |
|  | U+000B | Vertical Tab |
|  | U+000C | Form Feed |
|  | U+007F | Delete |
If your content is generated dynamically (from a database, API, or user input), sanitize the data before inserting it into HTML to strip out control characters. Most server-side languages and templating engines provide utilities for this purpose.
Character references are how HTML represents special characters that would otherwise be interpreted as markup or that aren’t easily typed on a keyboard. They come in three forms:
- Named references like &, <, ©
- Decimal numeric references like <, ©
- Hexadecimal numeric references like <, ©
All three forms share the same structure: they begin with & and must end with ;. When you omit the trailing semicolon, the HTML parser enters error recovery mode. Depending on the context, it may still resolve the reference (browsers are lenient), but this behavior is not guaranteed and varies across situations. For example, © without a semicolon might still render as ©, but ¬it could be misinterpreted as the ¬ (¬) reference followed by it, producing unexpected output like “¬it” instead of the literal text “¬it”.
Why this matters
- Unpredictable rendering: Without the semicolon, browsers use heuristic error recovery that can produce different results depending on surrounding text. What looks fine today might break with different adjacent characters.
- Standards compliance: The WHATWG HTML specification requires the semicolon terminator. Omitting it is a parse error.
- Maintainability: Other developers (or future you) may not realize the ampersand was intended as a character reference, making the code harder to read and maintain.
- Data integrity: In URLs within href attributes, a missing semicolon on a character reference can corrupt query parameters and produce broken links.
How to fix it
- Add the missing semicolon to the end of every character reference.
- If you meant a literal ampersand, use & instead of a bare &. This is especially common in URLs with query strings.
- Search your document for patterns like &something without a trailing ; to catch all instances.
Examples
❌ Missing semicolon on named references
<p>5 < 10 and 10 > 5</p>
<p>© 2024 All rights reserved</p>
✅ Properly terminated named references
<p>5 < 10 and 10 > 5</p>
<p>© 2024 All rights reserved</p>
❌ Missing semicolon on numeric references
<p>The letter A: A</p>
<p>Hex example: A</p>
✅ Properly terminated numeric references
<p>The letter A: A</p>
<p>Hex example: A</p>
❌ Bare ampersand in a URL (common mistake)
<a href="https://example.com/search?name=alice&age=30">Search</a>
Here the validator sees &age and tries to interpret it as a character reference without a semicolon.
✅ Escaped ampersand in a URL
<a href="https://example.com/search?name=alice&age=30">Search</a>
❌ Ambiguous reference causing wrong output
<p>The entity ¬it; doesn't exist, but ¬ without a semicolon resolves to ¬</p>
✅ Use & when you want a literal ampersand
<p>The text &notit is displayed literally when properly escaped.</p>
A quick rule of thumb: every & in your HTML should either be the start of a complete, semicolon-terminated character reference, or it should itself be written as &.
Ready to validate your sites?
Start your free trial today.