HTML Guides for meta
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 character encoding declaration tells the browser how to interpret the raw bytes of your document into readable characters. For HTML documents, the standard way to declare this is with <meta charset="utf-8">. The HTML specification requires that this element be serialized completely within the first 1024 bytes of the document. This means that everything from the start of the file—including the doctype, the <html> tag, the <head> tag, and the <meta charset> element itself—must fit within that 1024-byte window.
If the <meta charset> element appears after the first 1024 bytes, the browser must use other heuristics or fallback encodings to guess how to decode the document. This can cause several problems:
- Garbled or broken text: Characters outside the ASCII range (such as accented letters, CJK characters, or emoji) may render incorrectly.
- Security vulnerabilities: Certain encoding-sniffing behaviors have historically been exploited for cross-site scripting (XSS) attacks, which is one reason the spec enforces this strict limit.
- Inconsistent rendering: Different browsers may fall back to different default encodings, meaning your page could look different depending on the user's browser or system locale.
This issue typically occurs when a large number of <meta> tags, inline <style> blocks, lengthy comments, or <script> elements are placed in the <head> before the <meta charset> declaration. Even excessive whitespace or server-injected content can push it past the 1024-byte boundary.
To fix this, ensure that <meta charset="utf-8"> is the first child element of <head>, appearing before any <title>, <link>, <script>, <style>, or other <meta> tags. Remove or relocate any unnecessary content that precedes it.
Examples
❌ Incorrect: <meta charset> pushed past 1024 bytes
In this example, a large inline style block and several meta tags appear before the charset declaration, easily exceeding the 1024-byte limit:
<!DOCTYPE html>
<htmllang="en">
<head>
<metaname="description"content="A very long description...">
<metaname="keywords"content="many, keywords, here, ...">
<metaname="author"content="Some Author">
<linkrel="stylesheet"href="styles.css">
<style>
/* Hundreds of bytes of inline CSS rules... ...pushing the total well past 1024 bytes before the charset declaration appears */
...pushing the total well past 1024 bytes
before the charset declaration appears */
body{font-family: sans-serif;margin:0;padding:0;}
.container{max-width:1200px;margin:0 auto;}
/* ...many more rules... */
</style>
<metacharset="utf-8">
<title>My Page</title>
</head>
<body>
<p>Hello world</p>
</body>
</html>
✅ Correct: <meta charset> as the first element in <head>
Move the charset declaration to the very first position inside <head>:
<!DOCTYPE html>
<htmllang="en">
<head>
<metacharset="utf-8">
<title>My Page</title>
<metaname="description"content="A very long description...">
<metaname="keywords"content="many, keywords, here, ...">
<metaname="author"content="Some Author">
<linkrel="stylesheet"href="styles.css">
<style>
body{font-family: sans-serif;margin:0;padding:0;}
.container{max-width:1200px;margin:0 auto;}
</style>
</head>
<body>
<p>Hello world</p>
</body>
</html>
✅ Minimal correct example
For simpler documents, the pattern is straightforward—just keep <meta charset> first:
<!DOCTYPE html>
<htmllang="en">
<head>
<metacharset="utf-8">
<title>My Page</title>
</head>
<body>
<p>Hello world</p>
</body>
</html>
As a general rule of thumb, always make <meta charset="utf-8"> the very first thing after the opening <head> tag. This guarantees it falls well within the 1024-byte limit regardless of what follows, and it ensures the browser knows the correct encoding before it encounters any other content.
Both <meta charset="UTF-8"> and <meta http-equiv="content-type" content="text/html; charset=UTF-8"> instruct the browser which character encoding to use when interpreting the document's bytes into text. Having both declarations in the same document creates a redundant and potentially conflicting situation. The HTML specification explicitly forbids including both, because if they ever specified different encodings, the browser would have to decide which one to trust, leading to unpredictable behavior.
Character encoding is critical for correctly displaying text. If the encoding is wrong or ambiguous, characters like accented letters, emoji, or symbols from non-Latin scripts can appear as garbled text (often called "mojibake"). By requiring a single, unambiguous declaration, the spec ensures browsers can reliably determine the encoding.
The <meta charset="UTF-8"> syntax was introduced with HTML5 as a shorter, cleaner alternative to the older <meta http-equiv="content-type"> approach. Both are valid on their own, but modern best practice strongly favors <meta charset="UTF-8"> for its simplicity. Whichever you choose, it should appear as early as possible within the <head> element — ideally as the first child — and must appear within the first 1024 bytes of the document so the browser can detect the encoding before parsing the rest of the content.
To fix this issue, search your document's <head> for both forms of the declaration and remove one of them. In most cases, you should keep <meta charset="UTF-8"> and remove the <meta http-equiv="content-type"> element.
Examples
Incorrect: both declarations present
This triggers the validation error because both methods of declaring the character encoding are used simultaneously.
<!DOCTYPE html>
<htmllang="en">
<head>
<metacharset="UTF-8">
<metahttp-equiv="content-type"content="text/html; charset=UTF-8">
<title>My Page</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
Correct: using <meta charset> (recommended)
This is the modern, preferred approach for HTML5 documents.
<!DOCTYPE html>
<htmllang="en">
<head>
<metacharset="UTF-8">
<title>My Page</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
Correct: using <meta http-equiv="content-type">
This older syntax is also valid on its own. You might encounter it in legacy codebases or when serving documents as application/xhtml+xml.
<!DOCTYPE html>
<htmllang="en">
<head>
<metahttp-equiv="content-type"content="text/html; charset=UTF-8">
<title>My Page</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
Common scenario: declarations split across includes
In templating systems or CMS platforms, the two declarations sometimes end up in different partial files — for example, one in a base layout and another injected by a plugin or theme. If you encounter this error unexpectedly, check all files that contribute to your <head> section, not just the main template.
<!-- base-layout.html -->
<head>
<metacharset="UTF-8">
<!-- ...other tags... -->
</head>
<!-- plugin-head-snippet.html (remove this duplicate) -->
<metahttp-equiv="content-type"content="text/html; charset=UTF-8">
Audit your includes and partials to ensure only one character encoding declaration ends up in the final rendered <head>.
The <meta charset> element tells the browser which character encoding to use when interpreting the bytes of the HTML document. The HTML specification explicitly states that there must be no more than one <meta> element with a charset attribute per document. This declaration should appear within the first 1024 bytes of the document, so placing it as the first child of <head> (right after the opening <head> tag) is the recommended practice.
Duplicate charset declarations typically happen when code is assembled from multiple templates, partials, or snippets — each contributing its own <meta charset>. It can also occur when a developer manually adds a charset declaration without realizing one is already present, or when migrating from an older <meta http-equiv="Content-Type"> approach and adding a new <meta charset> without removing the old equivalent.
Why this matters
- Standards compliance: The WHATWG HTML living standard mandates at most one
<meta charset>per document. Violating this produces a validation error. - Unpredictable behavior: When a browser encounters conflicting or duplicate charset declarations, the behavior is undefined. While most modern browsers will use the first one encountered, relying on this is fragile and could lead to garbled text or encoding issues in edge cases.
- Maintainability: Multiple charset declarations signal disorganized or duplicated template logic, making the codebase harder to maintain.
How to fix it
- Search your HTML document (including any templates, layouts, or partials that compose the final output) for all instances of
<meta charset>or<meta charset="...">. - Keep exactly one
<meta charset="utf-8">declaration, placed as the first element inside<head>. - Remove all other
<meta charset>elements. - If you also have a legacy
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">, remove it — the shorter<meta charset="utf-8">form is the modern replacement, and having both counts as duplicate charset declarations.
Examples
❌ Incorrect: multiple charset declarations
<!DOCTYPE html>
<htmllang="en">
<head>
<metacharset="utf-8">
<metacharset="utf-8">
<title>My Page</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
The second <meta charset="utf-8"> triggers the validation error, even though both specify the same encoding.
❌ Incorrect: mixing old and new charset syntax
<!DOCTYPE html>
<htmllang="en">
<head>
<metacharset="utf-8">
<metahttp-equiv="Content-Type"content="text/html; charset=utf-8">
<title>My Page</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
Both elements declare a character encoding, so the validator treats this as a duplicate.
✅ Correct: single charset declaration
<!DOCTYPE html>
<htmllang="en">
<head>
<metacharset="utf-8">
<title>My Page</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
A single <meta charset="utf-8"> appears first in <head>, before any other elements or content. This is the correct and recommended approach. UTF-8 is the strongly recommended encoding for all new HTML documents.
The <meta name="description"> element provides a brief summary of a page's content. According to the WHATWG HTML living standard, there must be no more than one <meta> element per document where the name attribute has the value "description". This is a conformance requirement — not just a best practice — meaning that including duplicates produces invalid HTML.
Why this matters
Standards compliance: The HTML specification explicitly states that certain metadata names, including "description", must be unique within a document. Violating this makes your HTML non-conforming.
Search engine behavior: Search engines like Google use the meta description to generate snippet text in search results. When multiple description meta tags are present, search engines must decide which one to use — or may ignore them entirely and pull text from the page body instead. This can result in a less relevant or less compelling snippet, potentially reducing click-through rates.
Maintainability: Duplicate meta descriptions often arise from template conflicts — for example, a CMS injecting one description while a theme or plugin adds another. Having duplicates makes it unclear which description is actually intended, creating confusion for developers maintaining the code.
Common causes
- A CMS or static site generator automatically inserts a
<meta name="description">tag, while the template or theme also hardcodes one. - Multiple HTML partials or includes each contribute their own description meta tag to the
<head>. - Copy-paste errors when building or editing the
<head>section.
How to fix it
- Search your HTML source for all instances of
<meta name="description". - Decide which description best represents the page's content.
- Remove all duplicate instances, keeping only one.
- If your content comes from templates or includes, trace where each tag is generated and ensure only one source outputs the description.
Examples
❌ Invalid: duplicate description meta tags
<!DOCTYPE html>
<htmllang="en">
<head>
<title>About Us</title>
<metaname="description"content="Learn about our company and mission.">
<metaname="description"content="We are a team of passionate developers.">
</head>
<body>
<h1>About Us</h1>
<p>Welcome to our about page.</p>
</body>
</html>
The validator will report an error because two <meta> elements share name="description".
✅ Valid: single description meta tag
<!DOCTYPE html>
<htmllang="en">
<head>
<title>About Us</title>
<metaname="description"content="Learn about our company, mission, and the team of passionate developers behind it.">
</head>
<body>
<h1>About Us</h1>
<p>Welcome to our about page.</p>
</body>
</html>
Here, the two descriptions have been merged into a single, more comprehensive meta description. Alternatively, you could simply keep whichever original description was more accurate and discard the other.
❌ Invalid: duplicates from mixed sources (common template issue)
<head>
<title>Blog Post</title>
<!-- Injected by CMS -->
<metaname="description"content="Auto-generated summary of the blog post.">
<!-- Hardcoded in theme template -->
<metaname="description"content="A blog about web development tips and tricks.">
<metaname="author"content="Jane Smith">
</head>
✅ Valid: single source of truth
<head>
<title>Blog Post</title>
<!-- Injected by CMS (theme duplicate removed) -->
<metaname="description"content="Auto-generated summary of the blog post.">
<metaname="author"content="Jane Smith">
</head>
When fixing template-driven duplicates, decide which system should own the description — typically the CMS, since it can generate page-specific descriptions — and remove the hardcoded one from the theme.
Make sure your final <meta name="description"> content is meaningful, concise (typically 150–160 characters), and accurately reflects what visitors will find on the page.
The X-UA-Compatible meta tag was originally introduced to control which rendering engine Internet Explorer would use to display a page. Developers could force IE to emulate older versions (e.g., IE=7, IE=9) or use the latest available engine with IE=edge. The value IE=edge,chrome=1 was also commonly used to activate the Google Chrome Frame plugin, which allowed Internet Explorer to use Chrome's rendering engine instead.
The HTML specification now only permits the value IE=edge for this meta tag. Other values are considered invalid for several reasons:
- Google Chrome Frame is discontinued. The
chrome=1directive targeted a plugin that was retired in February 2014 and is no longer supported by any browser. - Legacy IE rendering modes are obsolete. Internet Explorer itself has been retired, making emulation modes like
IE=EmulateIE7orIE=9pointless. - Standards compliance. The WHATWG HTML living standard explicitly requires the
contentattribute value to beIE=edgewhenhttp-equiv="X-UA-Compatible"is used.
In practice, since all modern browsers use their latest rendering engine by default, this meta tag has little functional impact today. If your site no longer needs to support Internet Explorer at all, you can safely remove the tag entirely. If you choose to keep it — for example, in environments where legacy IE browsers might still access your site — ensure the value is exactly IE=edge.
Examples
Invalid: Using chrome=1 with IE=edge
This was a common pattern when Google Chrome Frame was active, but it now triggers a validation error:
<metahttp-equiv="X-UA-Compatible"content="IE=edge,chrome=1">
Invalid: Using a legacy IE rendering mode
Forcing a specific IE version is no longer valid:
<metahttp-equiv="X-UA-Compatible"content="IE=EmulateIE7">
Invalid: Specifying a particular IE version
<metahttp-equiv="X-UA-Compatible"content="IE=9">
Valid: Using IE=edge
The only accepted value is IE=edge:
<metahttp-equiv="X-UA-Compatible"content="IE=edge">
Valid: Removing the tag entirely
If you don't need Internet Explorer compatibility, the simplest fix is to remove the meta tag altogether. A minimal valid document without it:
<!DOCTYPE html>
<htmllang="en">
<head>
<metacharset="utf-8">
<title>My Page</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
The <meta charset="utf-8"> declaration is not only valid but recommended by the HTML living standard. So when the validator complains that the charset attribute is "not allowed at this point," the problem isn't the <meta> tag itself — it's what surrounds it. The HTML parser follows strict rules about which elements can appear inside <head>. When it encounters an element that doesn't belong there (like <img>, <div>, <p>, or other flow/phrasing content), it implicitly closes the <head> and opens the <body>. Any <meta> tags that come after that point are now parsed as being inside <body>, where <meta charset> is not permitted.
This is a problem for several reasons. First, the <meta charset> declaration must appear within the first 1024 bytes of the document so browsers can determine the character encoding early. If the parser moves it out of <head>, browsers may not apply the encoding correctly, potentially leading to garbled text — especially for non-ASCII characters. Second, this often signals a structural error in your HTML that could cause other unexpected rendering issues.
Common causes include:
- An element that only belongs in
<body>(like<img>,<div>,<span>, or<p>) placed before<meta charset>in the<head>. - A stray closing tag (like
</head>) appearing too early. - A
<script>tag with content that causes the parser to break out of<head>.
To fix the issue, inspect the elements that appear before <meta charset> in your <head>. Move any elements that don't belong in <head> into <body>, and place <meta charset="utf-8"> as the very first element inside <head>.
Examples
Incorrect — element before <meta> forces parser out of <head>
An <img> tag inside <head> causes the parser to implicitly close <head> and open <body>. The <meta charset> that follows is now parsed as being in <body>, triggering the error.
<!DOCTYPE html>
<htmllang="en">
<head>
<title>My Page</title>
<imgsrc="photo.jpg"alt="A smiling cat">
<metacharset="utf-8">
</head>
<body>
<p>Some content</p>
</body>
</html>
Correct — <meta charset> first, invalid elements moved to <body>
<!DOCTYPE html>
<htmllang="en">
<head>
<metacharset="utf-8">
<title>My Page</title>
</head>
<body>
<imgsrc="photo.jpg"alt="A smiling cat">
<p>Some content</p>
</body>
</html>
Incorrect — stray <div> in <head> breaks context
<!DOCTYPE html>
<htmllang="en">
<head>
<div>Oops</div>
<metacharset="utf-8">
<title>My Page</title>
</head>
<body>
<p>Hello</p>
</body>
</html>
Correct — only valid head elements before <meta charset>
<!DOCTYPE html>
<htmllang="en">
<head>
<metacharset="utf-8">
<title>My Page</title>
</head>
<body>
<div>Content goes here</div>
<p>Hello</p>
</body>
</html>
Best practice
As a general rule, always make <meta charset="utf-8"> the very first child of <head>. This ensures the browser detects the encoding as early as possible and avoids the risk of other elements accidentally breaking the parser context before the charset is declared.
The http-equiv attribute on a <meta> element simulates an HTTP response header, allowing you to define document-level metadata that would otherwise require server configuration. Because this metadata applies to the entire document and must be processed before the page content is rendered, the HTML specification requires that <meta http-equiv> elements appear within the <head> element. Placing them in the <body> is invalid and may cause browsers to ignore them entirely, leading to unexpected behavior like incorrect character encoding, broken content security policies, or missing refresh directives.
This error commonly occurs when:
- A
<meta http-equiv>tag is accidentally placed inside<body>. - Content is copy-pasted from one document into the body of another, bringing along
<meta>tags. - A templating system or CMS injects
<meta>tags in the wrong location.
Common http-equiv values
The http-equiv attribute supports several standard values:
content-type— Declares the document's MIME type and character encoding. In HTML5, the shorthand<meta charset="UTF-8">is preferred instead.refresh— Instructs the browser to reload the page or redirect after a specified number of seconds. Note that automatic refreshing is discouraged for accessibility reasons: it can disorient users, move focus back to the top of the page, and disrupt assistive technology. Avoid it unless absolutely necessary.content-security-policy— Defines a Content Security Policy for the document, helping prevent cross-site scripting (XSS) and other code injection attacks.default-style— Specifies the preferred stylesheet from a set of alternative stylesheets.
How to fix it
Find every <meta http-equiv> element in your document and ensure it is placed inside the <head> element, before any content in <body>. If the tag is duplicated or unnecessary, remove it.
Examples
❌ Incorrect: http-equiv inside <body>
<!DOCTYPE html>
<htmllang="en">
<head>
<title>My Page</title>
</head>
<body>
<metahttp-equiv="content-type"content="text/html; charset=UTF-8">
<p>Hello, world!</p>
</body>
</html>
The <meta http-equiv> tag is inside <body>, which triggers the validation error.
✅ Correct: http-equiv inside <head>
<!DOCTYPE html>
<htmllang="en">
<head>
<metahttp-equiv="content-type"content="text/html; charset=UTF-8">
<title>My Page</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
✅ Correct: using the HTML5 charset shorthand
In HTML5, you can replace <meta http-equiv="content-type" content="text/html; charset=UTF-8"> with the simpler charset attribute:
<!DOCTYPE html>
<htmllang="en">
<head>
<metacharset="UTF-8">
<title>My Page</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
✅ Correct: Content Security Policy in <head>
<head>
<metacharset="UTF-8">
<metahttp-equiv="content-security-policy"content="default-src 'self'">
<title>Secure Page</title>
</head>
The content-security-policy value is particularly placement-sensitive — browsers will ignore it if it appears outside <head>, leaving your page without the intended security protections.
This error is misleading at first glance because the <meta> tag in question is often perfectly well-formed. The real problem is usually above the <meta> tag — an element that doesn't belong in <head> (such as <img>, <div>, <p>, or other flow content) has been placed there. When the HTML parser encounters such an element inside <head>, it implicitly closes the <head> and opens the <body>. From that point on, any subsequent <meta> tags are now technically inside the <body>, where the name attribute on <meta> is not permitted.
In other cases, the error can also occur when a <meta name="..."> tag is explicitly placed inside <body>, or when a typo or malformed tag earlier in the document breaks the expected document structure.
This matters for several reasons. Search engines and social media platforms rely on <meta> tags being in the <head> to extract page descriptions, Open Graph data, and other metadata. If the document structure is broken and <meta> tags end up in the <body>, this metadata may be ignored entirely. Additionally, elements like <img> inside <head> won't render as expected, and the overall document structure will be invalid, potentially causing unpredictable behavior across browsers.
How to fix it
- Look above the flagged
<meta>tag. Find any element in the<head>that doesn't belong there — common culprits include<img>,<div>,<span>,<p>,<a>, or<section>. - Move the offending element into the
<body>where it belongs. - If the
<meta>tag itself is in the<body>, move it into the<head>. - Check for malformed tags above the
<meta>— an unclosed tag or a typo can break the parser's understanding of the document structure.
Only certain elements are allowed inside <head>: <title>, <meta>, <link>, <style>, <script>, <noscript>, <base>, and <template>.
Examples
An invalid element in <head> breaks the context
The <img> tag is not allowed inside <head>. The parser implicitly closes <head> when it encounters it, so the <meta> tag that follows ends up in <body>:
<!DOCTYPE html>
<htmllang="en">
<head>
<title>My Page</title>
<imgsrc="photo.jpg"alt="A smiling cat">
<metaname="description"content="A page about cats">
</head>
<body>
<p>Welcome!</p>
</body>
</html>
Move the <img> into the <body> to fix the issue:
<!DOCTYPE html>
<htmllang="en">
<head>
<title>My Page</title>
<metaname="description"content="A page about cats">
</head>
<body>
<imgsrc="photo.jpg"alt="A smiling cat">
<p>Welcome!</p>
</body>
</html>
A <meta> tag accidentally placed in <body>
<!DOCTYPE html>
<htmllang="en">
<head>
<title>My Page</title>
</head>
<body>
<metaname="author"content="Jane Doe">
<p>Hello world</p>
</body>
</html>
Move the <meta> tag into <head>:
<!DOCTYPE html>
<htmllang="en">
<head>
<title>My Page</title>
<metaname="author"content="Jane Doe">
</head>
<body>
<p>Hello world</p>
</body>
</html>
A malformed tag disrupts the <head>
A missing closing > on a <link> tag can confuse the parser, causing subsequent elements to be misinterpreted:
<!DOCTYPE html>
<htmllang="en">
<head>
<title>My Page</title>
<linkrel="stylesheet"href="style.css"
<metaname="viewport"content="width=device-width, initial-scale=1">
</head>
<body>
<p>Content</p>
</body>
</html>
Close the <link> tag properly:
<!DOCTYPE html>
<htmllang="en">
<head>
<title>My Page</title>
<linkrel="stylesheet"href="style.css">
<metaname="viewport"content="width=device-width, initial-scale=1">
</head>
<body>
<p>Content</p>
</body>
</html>
The Accept-CH value is not a valid value for the http-equiv attribute on a <meta> element according to the HTML specification.
The http-equiv attribute on <meta> only accepts a specific set of values defined in the HTML standard. These include content-type, default-style, refresh, x-ua-compatible, and content-security-policy. The Accept-CH header is used for Client Hints, which lets the server request specific information from the browser (like device width or viewport size), but it must be delivered as an actual HTTP response header from the server — not as an HTML <meta> tag.
While some browsers may process Accept-CH in a <meta> tag, this behavior is non-standard and not universally supported. The W3C validator correctly flags it as invalid. To fix this, move the Accept-CH directive to your server's HTTP response headers.
Invalid Example
<head>
<metahttp-equiv="Accept-CH"content="DPR, Viewport-Width, Width">
<title>My Page</title>
</head>
How to Fix
Remove the <meta> tag and configure your server to send the header instead. For example, in an Apache .htaccess file:
Header set Accept-CH "DPR, Viewport-Width, Width"
Or in Nginx:
add_header Accept-CH "DPR, Viewport-Width, Width";
This ensures the Client Hints are delivered through a proper HTTP header, which is both valid and more reliably supported across browsers.
The http-equiv attribute on the <meta> element is designed to simulate certain HTTP response headers when a server isn't configured to send them directly. However, the HTML specification only permits a limited set of values for this attribute. According to the WHATWG HTML living standard, the valid http-equiv values are:
content-type— an alternative way to declare character encodingdefault-style— sets the preferred stylesheetrefresh— redirects or reloads the page after a delayx-ua-compatible— specifies document compatibility mode for Internet Explorercontent-security-policy— declares a content security policy
Using Cache-Control as an http-equiv value is a pattern that originated in early web development, when some browsers attempted to honor cache directives set through <meta> tags. In practice, modern browsers ignore <meta http-equiv="Cache-Control"> entirely. Caching behavior is determined by actual HTTP response headers sent by the server, not by <meta> tags in the document body. This means the tag not only triggers a validation error but also has no practical effect — it gives a false sense of control over caching while doing nothing.
This matters for several reasons. Invalid HTML can cause unexpected behavior in browsers, particularly edge cases with older or less common user agents. It also undermines confidence in your markup — if a validator flags issues, it becomes harder to spot genuinely important errors. Additionally, relying on a non-functional tag for caching can lead to real problems if developers assume caching is being handled when it isn't.
The correct approach is to configure cache-control headers on your web server or application layer. Every major web server and framework provides a straightforward way to set Cache-Control HTTP headers.
For Apache, you can add this to your .htaccess or server configuration:
Header set Cache-Control "no-cache, no-store, must-revalidate"
For Nginx, use:
add_header Cache-Control "no-cache, no-store, must-revalidate";
In a Node.js/Express application:
res.set('Cache-Control','no-cache, no-store, must-revalidate');
Examples
Invalid: Using Cache-Control as an http-equiv value
<!DOCTYPE html>
<htmllang="en">
<head>
<title>My Page</title>
<metahttp-equiv="Cache-Control"content="no-cache">
<metahttp-equiv="Pragma"content="no-cache">
<metahttp-equiv="Expires"content="0">
</head>
<body>
<p>This page attempts to control caching via meta tags.</p>
</body>
</html>
In this example, all three <meta> tags are problematic. Cache-Control and Pragma are not valid http-equiv values. While Expires was historically used, it is also not in the current list of conforming values in the WHATWG specification.
Fixed: Removing invalid <meta> tags
<!DOCTYPE html>
<htmllang="en">
<head>
<title>My Page</title>
<!-- Cache-Control should be set via server HTTP headers -->
</head>
<body>
<p>Caching is now properly handled server-side.</p>
</body>
</html>
The invalid <meta> tags are removed entirely. Cache behavior is configured on the server, where it actually takes effect.
Valid: Using a permitted http-equiv value
<!DOCTYPE html>
<htmllang="en">
<head>
<title>Redirecting</title>
<metahttp-equiv="refresh"content="5;url=https://example.com">
</head>
<body>
<p>You will be redirected in 5 seconds.</p>
</body>
</html>
This example uses refresh, which is a valid http-equiv value. It demonstrates what the attribute is actually designed for — a small set of well-defined, browser-supported directives.
The http-equiv attribute on <meta> elements acts as a pragma directive, simulating the effect of an HTTP response header. The HTML specification defines a strict list of allowed values, including content-type, default-style, refresh, x-ua-compatible, and content-security-policy. Any value not on this list — such as cleartype — is considered invalid and will trigger a validation error.
The <meta http-equiv="cleartype" content="on"> tag was a proprietary Microsoft extension designed to activate ClearType text smoothing in Internet Explorer Mobile 6 and 7 on Windows Phone. ClearType is a sub-pixel rendering technology that improves the readability of text on LCD screens. Since these browsers are long obsolete, this meta tag serves no practical purpose today. No modern browser recognizes or acts on it.
Keeping invalid meta tags in your HTML has several downsides:
- Standards compliance: It produces W3C validation errors, which can mask other, more important issues in your markup.
- Code cleanliness: Dead code clutters your document head and confuses developers who may not know its history.
- No functional benefit: Since no current browser or rendering engine uses this directive, it provides zero value.
The fix is straightforward: remove the <meta http-equiv="cleartype"> tag. If your project requires smooth font rendering on modern browsers, CSS properties like font-smooth (non-standard) or -webkit-font-smoothing and -moz-osx-font-smoothing can be used instead, though these are also non-standard and should be used with care.
Examples
❌ Invalid: Using cleartype as an http-equiv value
<head>
<metacharset="utf-8">
<metahttp-equiv="cleartype"content="on">
<title>My Page</title>
</head>
This triggers the validation error because cleartype is not a valid value for http-equiv.
✅ Fixed: Remove the invalid meta tag
<head>
<metacharset="utf-8">
<title>My Page</title>
</head>
Simply removing the tag resolves the error with no loss of functionality in modern browsers.
✅ Alternative: Use CSS for font smoothing if needed
If you want to influence text rendering, use CSS instead of a non-standard meta tag:
body{
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
Note that these CSS properties are themselves non-standard and primarily affect macOS and iOS rendering. On Windows, modern browsers already apply ClearType or DirectWrite smoothing automatically without any developer intervention.
The http-equiv attribute on the <meta> element simulates HTTP response headers. However, the HTML living standard only allows a specific set of values for http-equiv, and Content-Script-Type is not among them. The allowed values include content-type, default-style, refresh, x-ua-compatible, and content-security-policy.
In HTML 4.01, <meta http-equiv="Content-Script-Type" content="text/javascript"> was used to tell the browser which scripting language to assume for inline event handlers (like onclick). Since JavaScript is now the only scripting language supported by browsers, this declaration serves no purpose. Every modern browser already assumes JavaScript by default, making this meta tag completely redundant.
Removing this tag has no effect on your page's behavior. Your scripts will continue to work exactly as before. If you're maintaining a legacy codebase, you can safely delete this line during any cleanup or modernization effort.
Examples
❌ Invalid: using Content-Script-Type
<head>
<metacharset="utf-8">
<metahttp-equiv="Content-Script-Type"content="text/javascript">
<title>My Page</title>
</head>
This triggers the validation error because Content-Script-Type is not a valid http-equiv value in modern HTML.
✅ Fixed: remove the obsolete meta tag
<head>
<metacharset="utf-8">
<title>My Page</title>
</head>
Simply remove the <meta http-equiv="Content-Script-Type"> line. No replacement is needed — browsers already default to JavaScript for all script handling.
✅ Valid http-equiv values for reference
Here are some examples of http-equiv values that are valid in modern HTML:
<head>
<metacharset="utf-8">
<metahttp-equiv="x-ua-compatible"content="IE=edge">
<metahttp-equiv="refresh"content="30">
<metahttp-equiv="content-security-policy"content="default-src 'self'">
<title>My Page</title>
</head>
The http-equiv attribute accepts a specific set of predefined values, and the validator checks both the value itself and its formatting. When the validator reports a bad value of ""Content-Security-Policy"" (note the doubled quotes), it means the actual attribute value being parsed includes literal quotation mark characters as part of the string. The browser sees the first " as opening the attribute, then immediately sees the second " as closing it — resulting in a malformed tag that won't work as intended.
This matters for several reasons. Content-Security-Policy delivered via a <meta> tag is a critical security mechanism that restricts which resources your page can load. If the tag is malformed, the browser will silently ignore the policy, leaving your site without the CSP protections you intended. There's no visual indication that the policy failed to apply, making this a particularly dangerous bug.
Common causes of this issue include:
- Copying code from a word processor or CMS that converts straight quotes (
") into curly/smart quotes ("and"). - Double-escaping in templates where a templating engine adds quotes around a value that already has quotes in the markup.
- Manual typos where quotes are accidentally duplicated.
To fix this, open your HTML source in a plain-text editor (not a word processor) and ensure the http-equiv value is wrapped in exactly one pair of standard straight double quotes with no extra quote characters inside.
Examples
Incorrect — doubled quotes around the value
<metahttp-equiv=""Content-Security-Policy"" content="default-src 'self';">
The validator interprets this as an http-equiv attribute with an empty value (""), followed by unrecognized content (Content-Security-Policy""), producing the error.
Incorrect — curly/smart quotes
<metahttp-equiv="Content-Security-Policy"content="default-src 'self';">
Smart quotes (" and ") are not valid attribute delimiters in HTML. They become part of the attribute value itself, causing the validator to reject it.
Incorrect — HTML entity quotes inside the attribute
<metahttp-equiv=""Content-Security-Policy""content="default-src 'self';">
Using " inside the attribute value embeds literal quote characters into the value string, which makes it invalid.
Correct — single pair of straight double quotes
<metahttp-equiv="Content-Security-Policy"content="default-src 'self';">
Correct — full document example
<!DOCTYPE html>
<htmllang="en">
<head>
<metacharset="UTF-8">
<metaname="viewport"content="width=device-width, initial-scale=1.0">
<metahttp-equiv="Content-Security-Policy"content="default-src 'self'; img-src https:; script-src 'self';">
<title>CSP Example</title>
</head>
<body>
<h1>Hello, World!</h1>
</body>
</html>
The http-equiv value Content-Security-Policy must be spelled exactly as shown — it is case-insensitive per the HTML spec, but using the canonical casing is recommended for clarity. The actual policy directives go in the content attribute, not in http-equiv. If you're using a templating engine or CMS, check the generated HTML source (via "View Page Source" in your browser) to confirm the output contains clean, straight quotes with no doubling.
Why This Is an Issue
In HTML 4 and XHTML, the Content-Style-Type HTTP header (and its <meta http-equiv> equivalent) told the browser which stylesheet language to use when interpreting inline style attributes and <style> elements. This was theoretically necessary because the specification allowed for alternative stylesheet languages beyond CSS.
In practice, CSS became the only stylesheet language browsers support. The HTML living standard (maintained by WHATWG) recognizes this reality and defines a strict list of valid http-equiv values. Content-Style-Type is not among them. The only valid values include content-type, default-style, refresh, x-ua-compatible, content-security-policy, and a few others defined in the spec.
Because every browser defaults to CSS for all styling, this meta tag serves no functional purpose. Keeping it in your markup only produces a validation error and adds unnecessary bytes to your document.
Similarly, the related Content-Script-Type meta tag (which declared the default scripting language) is also obsolete for the same reasons — JavaScript is the universal default.
How to Fix It
The fix is straightforward: remove the <meta http-equiv="Content-Style-Type" ...> tag from your document's <head>. No replacement is needed. Browsers will interpret all stylesheets as CSS and all scripts as JavaScript without any explicit declaration.
If you inherited this tag from a legacy template or an older CMS, you can safely delete it with no impact on your site's appearance or behavior.
Examples
❌ Invalid: Using the obsolete Content-Style-Type pragma
<head>
<metacharset="utf-8">
<metahttp-equiv="Content-Style-Type"content="text/css">
<title>My Page</title>
</head>
This triggers the validator error: Bad value "Content-Style-Type" for attribute "http-equiv" on element "meta".
✅ Valid: Simply remove the obsolete meta tag
<head>
<metacharset="utf-8">
<title>My Page</title>
</head>
No replacement is needed. CSS is already the default stylesheet language in all browsers.
❌ Invalid: Both Content-Style-Type and Content-Script-Type (common in legacy templates)
<head>
<metacharset="utf-8">
<metahttp-equiv="Content-Style-Type"content="text/css">
<metahttp-equiv="Content-Script-Type"content="text/javascript">
<title>Legacy Page</title>
</head>
✅ Valid: Remove both obsolete declarations
<head>
<metacharset="utf-8">
<title>Legacy Page</title>
</head>
Both Content-Style-Type and Content-Script-Type are obsolete. Removing them has zero effect on how browsers render your page, and your HTML will pass validation cleanly.
The http-equiv attribute on the <meta> element is designed to simulate certain HTTP response headers directly in HTML. However, the HTML specification only permits a specific set of values: content-type, default-style, refresh, x-ua-compatible, and content-security-policy. Using Expires as a value for http-equiv will trigger a validation error because it falls outside this permitted set.
Historically, some older browsers and HTML versions were more lenient about which values could appear in http-equiv, and developers commonly used <meta http-equiv="Expires" content="0"> or similar patterns to try to prevent page caching. However, this approach was never reliable — browsers and caching proxies handle actual HTTP headers far more consistently than <meta> tag equivalents. Modern HTML formally disallows this value.
Beyond standards compliance, there are practical reasons to avoid this pattern. Many browsers simply ignore unrecognized http-equiv values, meaning the tag does nothing useful. Cache behavior is best controlled at the HTTP level, where servers, CDNs, and proxies all read and respect the headers. Relying on a <meta> tag for caching gives a false sense of control while cluttering your markup with invalid code.
To fix this issue, remove the <meta http-equiv="Expires" ...> tag from your HTML and configure the Expires or Cache-Control HTTP header on your web server.
Examples
Incorrect: Using Expires in http-equiv
This triggers the validation error:
<head>
<metacharset="UTF-8">
<metahttp-equiv="Expires"content="0">
<metahttp-equiv="Expires"content="Tue, 01 Jan 2025 00:00:00 GMT">
<title>My Page</title>
</head>
Correct: Remove the invalid <meta> tag
Simply remove the offending tag. Only use valid http-equiv values:
<head>
<metacharset="UTF-8">
<title>My Page</title>
</head>
Correct: Valid uses of http-equiv
For reference, here are examples of valid http-equiv values:
<head>
<metacharset="UTF-8">
<metahttp-equiv="refresh"content="30">
<metahttp-equiv="content-security-policy"content="default-src 'self'">
<metahttp-equiv="default-style"content="main-stylesheet">
<title>My Page</title>
</head>
Correct: Set cache expiration via server configuration
The proper way to control caching is through HTTP response headers configured on your server.
Apache (.htaccess or server config):
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType text/html "access plus 1 day"
</IfModule>
Or using Cache-Control with mod_headers:
<IfModule mod_headers.c>
Header set Cache-Control "no-cache, no-store, must-revalidate"
Header set Expires "0"
</IfModule>
Nginx:
location~*\.html$ {
expires1d;
add_headerCache-Control"public, no-transform";
}
To prevent caching entirely in Nginx:
location~*\.html$ {
expires-1;
add_headerCache-Control"no-store, no-cache, must-revalidate";
}
If you don't have access to server configuration, many server-side languages let you set headers programmatically. For example, in PHP:
<?php
header("Expires: Tue, 01 Jan 2030 00:00:00 GMT");
header("Cache-Control: public, max-age=86400");
?>
By handling cache expiration at the server level, you get reliable behavior across all browsers, proxies, and CDNs — while keeping your HTML clean and standards-compliant.
This error is almost always caused by copying and pasting code from a word processor, CMS rich-text editor, blog post, or PDF. These tools often auto-correct straight quotation marks (") into typographic (curly or "smart") quotes (" and "). While curly quotes look nicer in prose, they are not valid as attribute delimiters in HTML. The browser and the W3C validator only recognize the standard straight double quote (", U+0022) or straight single quote (', U+0027) as attribute value delimiters.
When the validator encounters markup like <meta property="og:type", the curly quotes are treated as part of the attribute's value. The validator then sees the value as "og:type" — a string wrapped in literal curly quote characters. Since the property attribute in RDFa (which Open Graph Protocol relies on) expects a term or an absolute URL, and "og:type" is neither, the validator reports the error.
This problem can affect any HTML attribute, but it's especially common with <meta> tags for Open Graph, Twitter Cards, and other social sharing metadata, since developers frequently copy these snippets from documentation or tutorials.
How to fix it
- Find the curly quotes. Look at the
propertyattribute value in your source code. Curly opening quotes (", U+201C) and closing quotes (", U+201D) may look nearly identical to straight quotes in some fonts, so use your editor's find-and-replace feature to search for"and". - Replace them with straight quotes. Swap every
"and"with a standard straight double quote ("). - Disable smart quotes in your editor. If you're writing HTML in a rich-text editor or word processor, turn off the "smart quotes" or "typographic quotes" feature. Better yet, use a dedicated code editor (like VS Code, Sublime Text, or similar) that won't auto-replace quotes.
Examples
Incorrect — curly quotes around the attribute value
<metaproperty="og:type"content="website"/>
The curly " and " characters become part of the value itself, producing the validator error: Bad value "og:type" for attribute property.
Correct — straight quotes around the attribute value
<metaproperty="og:type"content="website"/>
Standard straight double quotes correctly delimit the attribute values, and the validator sees og:type as expected.
Correct — single straight quotes are also valid
<metaproperty='og:type'content='website'/>
Straight single quotes (', U+0027) work just as well as straight double quotes for delimiting HTML attribute values. Use whichever style your project prefers, but be consistent.
Full Open Graph example
<!DOCTYPE html>
<htmllang="en">
<head>
<metacharset="utf-8">
<title>My Page</title>
<metaproperty="og:title"content="My Page">
<metaproperty="og:type"content="website">
<metaproperty="og:url"content="https://example.com/">
<metaproperty="og:image"content="https://example.com/image.png">
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
All property and content attributes use straight double quotes, ensuring clean validation and correct parsing by social media crawlers.
The Pragma HTTP header is a holdover from HTTP/1.0, originally used to instruct proxies and browsers not to cache a response. In older HTML specifications, developers sometimes placed <meta http-equiv="Pragma" content="no-cache"> in their documents, hoping browsers would treat it like a real HTTP header. However, the HTML living standard (maintained by WHATWG) restricts the http-equiv attribute to a small set of recognized values: content-type, default-style, refresh, x-ua-compatible, and content-security-policy. The value Pragma is not among them, which is why the W3C validator flags it as invalid.
Beyond the validation error, this approach has always been unreliable. Browsers and caching proxies generally ignore http-equiv meta tags for cache control purposes — they rely on actual HTTP response headers sent by the server. Keeping this invalid tag in your HTML provides a false sense of security while producing no real caching benefit.
Why this is a problem
- Standards compliance: Using an unrecognized
http-equivvalue produces invalid HTML that fails W3C validation. - No practical effect: Most browsers and all intermediary proxies (CDNs, reverse proxies) ignore cache directives embedded in
<meta>tags. Only real HTTP headers reliably control caching behavior. - Misleading code: Developers maintaining the codebase may assume caching is properly managed in HTML when it isn't, leading to unexpected caching issues in production.
How to fix it
- Remove the invalid
<meta>tag from your HTML<head>. - Configure caching via HTTP response headers on your server. Set
Cache-Control(and optionallyPragmafor HTTP/1.0 compatibility) as actual headers in your server configuration or application code.
For example, in an Apache .htaccess file:
Header set Cache-Control "no-cache, no-store, must-revalidate"
Header set Pragma "no-cache"
Or in an Nginx configuration:
add_header Cache-Control "no-cache, no-store, must-revalidate";
add_header Pragma "no-cache";
These server-side headers are the correct and effective way to manage caching.
Examples
Incorrect: using Pragma in http-equiv
This triggers the validation error:
<head>
<metacharset="utf-8">
<metahttp-equiv="Pragma"content="no-cache">
<title>My Page</title>
</head>
Incorrect: using Cache-Control in http-equiv
While Cache-Control is also sometimes seen in <meta> tags, it is not a valid http-equiv value in the HTML standard either, and browsers largely ignore it:
<head>
<metacharset="utf-8">
<metahttp-equiv="Cache-Control"content="no-cache">
<title>My Page</title>
</head>
Correct: remove the invalid tag and use server headers
Simply remove the caching meta tag. Your HTML stays clean and valid:
<!DOCTYPE html>
<htmllang="en">
<head>
<metacharset="utf-8">
<title>My Page</title>
</head>
<body>
<p>Cache control is handled by server-side HTTP headers.</p>
</body>
</html>
Then configure your web server to send the appropriate Cache-Control and Pragma HTTP response headers as shown in the server configuration examples above. This is the only reliable way to control how browsers and proxies cache your pages.
The HTML5 specification mandates UTF-8 as the only permitted character encoding for web documents declared via <meta> tags. Legacy encodings such as windows-1251 (a Cyrillic character encoding), iso-8859-1, shift_jis, and others are no longer valid values in HTML5 <meta> declarations. This restriction exists because UTF-8 is a universal encoding that can represent virtually every character from every writing system, eliminating the interoperability problems that plagued the web when dozens of competing encodings were in use.
When the validator encounters content="text/html; charset=windows-1251" on a <meta> element, it flags it because the charset= portion must be followed by utf-8 — no other value is accepted. This applies whether you use the longer <meta http-equiv="Content-Type"> syntax or the shorter <meta charset> syntax.
Why this matters
- Standards compliance: The WHATWG HTML Living Standard explicitly requires
utf-8as the character encoding when declared in a<meta>tag. Non-conforming encodings will trigger validation errors. - Internationalization: UTF-8 supports all Unicode characters, making your pages work correctly for users across all languages, including Cyrillic text that
windows-1251was originally designed for. - Security: Legacy encodings can introduce security vulnerabilities, including certain cross-site scripting (XSS) attack vectors that exploit encoding ambiguity.
- Browser consistency: While browsers may still recognize legacy encodings, relying on them can cause mojibake (garbled text) when there's a mismatch between the declared and actual encoding.
How to fix it
- Update the
<meta>tag to declareutf-8as the charset. - Re-save your file in UTF-8 encoding using your text editor or IDE. Most modern editors support this — look for an encoding option in "Save As" or in the status bar.
- Verify your server configuration. If your server sends a
Content-TypeHTTP header with a different encoding, the server header takes precedence over the<meta>tag. Make sure both agree on UTF-8. - Convert your content. If your text was originally written in
windows-1251, you may need to convert it to UTF-8. Tools likeiconvon the command line can help:iconv -f WINDOWS-1251 -t UTF-8 input.html > output.html.
Examples
❌ Incorrect: Using windows-1251 charset
<metahttp-equiv="Content-Type"content="text/html; charset=windows-1251">
✅ Correct: Using utf-8 with http-equiv syntax
<metahttp-equiv="Content-Type"content="text/html; charset=utf-8">
✅ Correct: Using the shorter <meta charset> syntax (preferred in HTML5)
<metacharset="utf-8">
Full document example
<!DOCTYPE html>
<htmllang="ru">
<head>
<metacharset="utf-8">
<title>Пример страницы</title>
</head>
<body>
<p>Текст на русском языке в кодировке UTF-8.</p>
</body>
</html>
The shorter <meta charset="utf-8"> syntax is generally preferred in HTML5 documents because it's more concise and achieves the same result. Whichever syntax you choose, place the charset declaration within the first 1024 bytes of your document — ideally as the very first element inside <head> — so browsers can detect the encoding as early as possible.
The HTML specification mandates that documents must be encoded in UTF-8. This requirement exists because UTF-8 is the universal character encoding that supports virtually every character from every writing system in the world. Older encodings like windows-1252, iso-8859-1, or shift_jis only support a limited subset of characters and can cause text to display incorrectly — showing garbled characters or question marks — especially for users in different locales or when content includes special symbols, accented letters, or emoji.
When the validator encounters charset=windows-1252 in your <meta> tag, it flags this as an error because the HTML living standard (WHATWG) explicitly states that the character encoding declaration must specify utf-8 as the encoding. This isn't just a stylistic preference — browsers and other tools rely on this declaration to correctly interpret the bytes in your document. Using a non-UTF-8 encoding can lead to security vulnerabilities (such as encoding-based XSS attacks) and accessibility issues when assistive technologies misinterpret characters.
To fix this issue, take two steps:
- Update the
<meta>tag to declareutf-8as the charset. - Re-save your file with UTF-8 encoding. Most modern code editors (VS Code, Sublime Text, etc.) let you choose the encoding when saving — look for an option like "Save with Encoding" or check the status bar for the current encoding. If your file was originally in
windows-1252, simply changing the<meta>tag without re-encoding the file could cause existing special characters to display incorrectly.
The HTML spec also recommends using the shorter <meta charset="utf-8"> form rather than the longer <meta http-equiv="Content-Type" ...> pragma directive, as it's simpler and achieves the same result. Either form is valid, but the charset declaration must appear within the first 1024 bytes of the document.
Examples
Incorrect: Using windows-1252 charset
<metahttp-equiv="Content-Type"content="text/html; charset=windows-1252">
This triggers the validator error because the charset is not utf-8.
Correct: Using the short charset declaration (recommended)
<metacharset="utf-8">
Correct: Using the http-equiv pragma directive with utf-8
<metahttp-equiv="Content-Type"content="text/html; charset=utf-8">
Full document example
<!DOCTYPE html>
<htmllang="en">
<head>
<metacharset="utf-8">
<title>My Page</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
Note that the <meta charset="utf-8"> tag should be the first element inside <head>, before any other elements (including <title>), so the browser knows the encoding before it starts parsing the rest of the document.
The http-equiv attribute on the <meta> element does not accept "title" as a valid value.
The http-equiv attribute is designed to simulate specific HTTP response headers. It only accepts a limited set of predefined values: content-type, default-style, refresh, x-ua-compatible, and content-security-policy. Using "title" is not among these valid values and will trigger a validation error.
If you want to set the title of your page, use the <title> element inside <head> instead. The <title> element is the correct and standard way to define the document's title, which appears in the browser tab and is used by search engines.
Bad Example
<head>
<metahttp-equiv="title"content="My Page Title">
</head>
Good Example
<head>
<title>My Page Title</title>
</head>
The http-equiv attribute contains a misspelled or invalid value.
The http-equiv attribute on the <meta> element acts as a pragma directive, simulating an HTTP response header. The HTML specification only allows a specific set of values for this attribute. The valid values include content-type, default-style, refresh, X-UA-Compatible, and content-security-policy.
The value X-UA-Compatible was historically used to tell Internet Explorer to use a specific rendering engine. While it's largely obsolete now that IE is no longer supported, the HTML spec still recognizes it as a valid value.
Common mistakes that trigger this error include:
- Typos like
X-UA-Complatible,X-UA-Compatable, orX-UA-Compatble - Using non-standard values like
imagetoolbar,cleartype, orcache-control - Using values that were valid in older HTML versions but are no longer recognized
HTML Examples
❌ Invalid: misspelled value
<metahttp-equiv="X-UA-Complatible"content="IE=edge,chrome=1"/>
✅ Valid: correctly spelled value
<metahttp-equiv="X-UA-Compatible"content="IE=edge"/>
Note that the chrome=1 portion referenced Google Chrome Frame, a discontinued plugin. It's safe to remove it along with the entire <meta> tag if you no longer need to support Internet Explorer.
Changing the character encoding declaration too late in the document prevents the browser from processing it correctly. The <meta charset> declaration must appear within the first 1024 bytes of the HTML document, and specifically before any non-ASCII content.
When a browser parses an HTML document, it reads the bytes as a stream. If it encounters a <meta charset> tag after it has already started interpreting content, it would need to go back and re-parse everything from the beginning — this is "non-streamable behavior." To avoid this, the HTML specification requires that the charset declaration appear very early in the document.
The most common causes of this error are:
- Placing
<meta charset>after other large<meta>tags, long<title>content, or<script>blocks in the<head>. - Placing
<meta charset>after content that pushes it beyond the 1024-byte boundary. - Including it in the
<body>instead of the<head>.
The fix is simple: make <meta charset="utf-8"> the very first element inside <head>, before any other elements.
Incorrect Example
<!DOCTYPE html>
<htmllang="en">
<head>
<title>A very long title that takes up many bytes and pushes the charset declaration further down in the document stream...</title>
<metaname="description"content="A very long description with lots of text that consumes bytes before the charset is declared...">
<metacharset="utf-8">
</head>
<body>
<p>Hello world</p>
</body>
</html>
Corrected Example
<!DOCTYPE html>
<htmllang="en">
<head>
<metacharset="utf-8">
<title>A very long title that takes up many bytes...</title>
<metaname="description"content="A very long description with lots of text...">
</head>
<body>
<p>Hello world</p>
</body>
</html>
Always keep <meta charset="utf-8"> as the first child of <head>. This ensures the browser knows the encoding before it processes any other content.
When you set user-scalable=no in your viewport meta tag, the browser completely disables pinch-to-zoom and other scaling gestures on mobile devices. Similarly, setting maximum-scale=1 (or any low value) caps how far a user can zoom in, effectively locking them out of enlarging content. While developers sometimes use these values to create an "app-like" experience or prevent layout issues during zoom, they directly violate accessibility best practices.
Why this is a problem
Accessibility
The Web Content Accessibility Guidelines (WCAG) Success Criterion 1.4.4 (Resize Text) requires that text can be resized up to 200% without loss of content or functionality. Preventing zoom makes it impossible for users with low vision, cognitive disabilities, or motor impairments to interact comfortably with your page. Many users depend on pinch-to-zoom as their primary way to read content on mobile devices.
Standards compliance
The W3C HTML Validator flags this as a warning because it conflicts with established accessibility standards. While it won't cause your page to fail validation outright, it signals a practice that harms usability. Modern browsers and operating systems have also started to override restrictive viewport settings in some cases — for example, iOS Safari ignores user-scalable=no by default — which means the restriction may not even work as intended while still triggering warnings.
User experience
Even for users without disabilities, preventing zoom can be frustrating. Small text, dense layouts, or content that doesn't quite fit a screen size can all benefit from the user being able to zoom in. Restricting this capability removes a fundamental browser feature that users expect.
How to fix it
- Remove
user-scalable=nofrom your viewport meta tag. If present, either delete it or set it toyes. - Remove or increase
maximum-scale. If you need to set it, use a value of5or higher. Ideally, remove it entirely and let the browser handle zoom limits. - Remove
minimum-scaleif it's set to1, as this can also restrict zoom behavior on some browsers when combined with other values. - Test your layout at various zoom levels to ensure content reflows properly and remains usable.
Examples
❌ Viewport that prevents zooming
<metaname="viewport"content="width=device-width, initial-scale=1, user-scalable=no">
This completely disables user zoom on supporting browsers.
❌ Viewport with restrictive maximum-scale
<metaname="viewport"content="width=device-width, initial-scale=1, maximum-scale=1.0">
This caps zoom at 100%, effectively preventing any meaningful zoom.
❌ Both restrictions combined
<metaname="viewport"content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
This is the most restrictive combination and is commonly seen in mobile-first frameworks and templates.
✅ Accessible viewport (recommended)
<metaname="viewport"content="width=device-width, initial-scale=1">
This sets a responsive viewport without restricting zoom at all. The browser's default zoom behavior is preserved, and users can scale freely.
✅ Accessible viewport with a generous maximum-scale
<metaname="viewport"content="width=device-width, initial-scale=1, maximum-scale=5">
If you have a specific reason to set maximum-scale, use a value of 5 or higher. This still allows substantial zoom while giving you some control over extreme zoom levels.
✅ Full document example
<!DOCTYPE html>
<htmllang="en">
<head>
<metacharset="utf-8">
<metaname="viewport"content="width=device-width, initial-scale=1">
<title>Accessible Page</title>
</head>
<body>
<h1>Welcome</h1>
<p>This page allows users to zoom freely.</p>
</body>
</html>
If your layout breaks when users zoom in, the solution is to fix the CSS — using relative units like em, rem, or percentages, and responsive design techniques — rather than disabling zoom. A well-built responsive layout should handle zoom gracefully without needing to restrict it.
The <meta> element provides metadata about the HTML document — information that isn't displayed on the page but is used by browsers, search engines, and other web services. According to the HTML specification, a <meta> tag without any of the recognized attributes is meaningless. The validator flags this because a bare <meta> element (or one with only unrecognized attributes) provides no useful metadata and likely indicates an error or incomplete tag.
This issue commonly occurs when a <meta> tag is left empty by accident, when an attribute name is misspelled (e.g., naem instead of name), or when a required attribute is accidentally deleted during editing.
Most <meta> use cases fall into a few patterns, each requiring specific attribute combinations:
charset— Used alone to declare the document's character encoding.name+content— Used together to define named metadata like descriptions, viewport settings, or author information.http-equiv+content— Used together to simulate an HTTP response header.property+content— Used together for Open Graph and similar RDFa-based metadata.itemprop+content— Used together for microdata annotations.
Note that content alone is not sufficient — it must be paired with name, http-equiv, property, or itemprop to have meaning.
Examples
Incorrect: bare <meta> tag with no attributes
This triggers the validation error because the <meta> element has no recognized attributes:
<meta>
Incorrect: misspelled attribute
A typo in the attribute name means the validator doesn't recognize it:
<metanane="description"content="An example page.">
Incorrect: content without a pairing attribute
The content attribute alone is not enough — it needs name, http-equiv, property, or itemprop:
<metacontent="some value">
Correct: character encoding with charset
<metacharset="UTF-8">
Correct: named metadata with name and content
<metaname="description"content="A brief description of the webpage.">
<metaname="viewport"content="width=device-width, initial-scale=1.0">
<metaname="author"content="Jane Doe">
Correct: HTTP-equivalent with http-equiv and content
<metahttp-equiv="X-UA-Compatible"content="IE=edge">
Correct: Open Graph metadata with property and content
<metaproperty="og:title"content="My Page Title">
<metaproperty="og:description"content="A summary of the page content.">
Correct: microdata with itemprop and content
<metaitemprop="name"content="Product Name">
Full document example
<!DOCTYPE html>
<htmllang="en">
<head>
<metacharset="UTF-8">
<metaname="viewport"content="width=device-width, initial-scale=1.0">
<metaname="description"content="A brief description of the webpage.">
<metaproperty="og:title"content="My Page Title">
<title>Example Page</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
How to fix
- Find the flagged
<meta>tag in your HTML source at the line number the validator reports. - Check for typos in attribute names — make sure
name,charset,http-equiv,property, oritempropis spelled correctly. - Add the missing attribute. Determine what the
<meta>tag is supposed to do and add the appropriate attribute(s). If you can't determine its purpose, it may be safe to remove it entirely. - Ensure proper pairing. If you're using
content, make sure it's paired withname,http-equiv,property, oritemprop. Thecharsetattribute is the only one that works on its own withoutcontent.
The <meta> element is used to provide metadata about an HTML document. According to the HTML specification, a <meta> element must serve a specific purpose, and that purpose is determined by its attributes. A bare <meta> tag or one with only a charset attribute in the wrong context will trigger this validation error.
There are several valid patterns for <meta> elements:
name+content: Standard metadata pairs (e.g., description, viewport, author).http-equiv+content: Pragma directives that affect how the browser processes the page.charset: Declares the document's character encoding (only valid once, in the<head>).itemprop+content: Microdata metadata, which can appear in both<head>and<body>.property+content: Used for Open Graph and RDFa metadata.
When a <meta> tag doesn't match any of these valid patterns, the validator raises this error. The most common causes are:
- Forgetting the
contentattribute when usingnameorproperty. - Using non-standard attributes without the required ones (e.g., only specifying a custom attribute).
- Placing a
charsetmeta in the<body>, where it's not valid. - Typos in attribute names like
contentsinstead ofcontent.
This matters for standards compliance and can also affect SEO and social sharing. Search engines and social media crawlers rely on properly formed <meta> tags to extract page information. Malformed tags may be silently ignored, meaning your metadata won't take effect.
Examples
Incorrect: <meta> with name but no content
<head>
<metacharset="utf-8">
<title>My Page</title>
<metaname="description">
</head>
The <meta name="description"> tag is missing its content attribute, so the validator reports the error.
Correct: <meta> with both name and content
<head>
<metacharset="utf-8">
<title>My Page</title>
<metaname="description"content="A brief description of the page.">
</head>
Incorrect: <meta> with property but no content
<head>
<metacharset="utf-8">
<title>My Page</title>
<metaproperty="og:title">
</head>
Correct: Open Graph <meta> with property and content
<head>
<metacharset="utf-8">
<title>My Page</title>
<metaproperty="og:title"content="My Page">
</head>
Incorrect: <meta> with only a non-standard attribute
<head>
<metacharset="utf-8">
<title>My Page</title>
<metaname="theme-color"value="#ff0000">
</head>
Here, value is not a valid attribute for <meta>. The correct attribute is content.
Correct: Using content instead of value
<head>
<metacharset="utf-8">
<title>My Page</title>
<metaname="theme-color"content="#ff0000">
</head>
Incorrect: Bare <meta> tag with no meaningful attributes
<head>
<metacharset="utf-8">
<title>My Page</title>
<meta>
</head>
A <meta> element with no attributes serves no purpose and should be removed entirely.
Correct: Using itemprop in the <body>
The itemprop attribute allows <meta> to be used within the <body> as part of microdata:
<body>
<divitemscopeitemtype="https://schema.org/Product">
<spanitemprop="name">Example Product</span>
<metaitemprop="sku"content="12345">
</div>
</body>
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