HTML Guides for html
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 reports this error when it encounters isolang on the <html> element because isolang is not a recognized attribute in any version of HTML. This typically happens when developers attempt to specify the document’s language but use an incorrect or made-up attribute name, possibly confusing it with ISO language code terminology.
The correct attribute for declaring a document’s language is lang. This attribute accepts a valid BCP 47 language tag, which in most cases is a simple two-letter ISO 639-1 code (like en for English, fr for French, or pt for Portuguese). You can also use extended subtags for regional variants, such as en-US for American English or pt-BR for Brazilian Portuguese.
Setting the lang attribute properly is important for several reasons:
- Accessibility: Screen readers use the lang attribute to select the correct pronunciation rules, ensuring content is read aloud accurately.
- SEO: Search engines use the language declaration to serve the right content to users based on their language preferences.
- Browser behavior: Browsers rely on lang for features like spell-checking, hyphenation, and selecting appropriate default fonts for the given language.
- Standards compliance: Only recognized attributes pass W3C validation, and valid markup ensures consistent, predictable behavior across browsers.
To fix this issue, simply replace isolang with lang on your <html> element. Keep the same language code value—it’s the attribute name that’s wrong, not the value.
Examples
❌ Incorrect: Using the invalid isolang attribute
<!DOCTYPE html>
<html isolang="pt">
<head>
<title>Minha Página</title>
</head>
<body>
<p>Olá, mundo!</p>
</body>
</html>
This triggers the error: Attribute “isolang” not allowed on element “html” at this point.
✅ Correct: Using the lang attribute
<!DOCTYPE html>
<html lang="pt">
<head>
<title>Minha Página</title>
</head>
<body>
<p>Olá, mundo!</p>
</body>
</html>
✅ Correct: Using a regional language subtag
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<title>Minha Página</title>
</head>
<body>
<p>Olá, mundo!</p>
</body>
</html>
Common language codes
Here are some frequently used ISO 639-1 language codes for the lang attribute:
- en — English
- es — Spanish
- fr — French
- de — German
- pt — Portuguese
- zh — Chinese
- ja — Japanese
- ar — Arabic
- ko — Korean
- ru — Russian
The multiple attribute tells the browser that the user can supply more than one value for a given input. For <input type="file">, it allows selecting multiple files at once. For <input type="email">, it allows entering a comma-separated list of email addresses. These are the only two input types that support the multiple attribute according to the HTML specification.
This validation error can appear for two distinct reasons, and sometimes both at once:
-
An invalid value is assigned to the boolean attribute. Boolean attributes in HTML follow strict rules. Valid syntaxes are: the attribute name alone (multiple), an empty string value (multiple=""), or the attribute’s own name as the value (multiple="multiple"). Any other value — including multiple="true", multiple="1", or multiple="yes" — is invalid.
-
The attribute is used on an unsupported input type. Placing multiple on input types like text, number, password, or url is not valid because those types don’t define behavior for this attribute. Browsers will simply ignore it, but it still constitutes invalid markup.
Why this matters
- Standards compliance: Invalid boolean attribute values violate the WHATWG HTML specification. While most browsers are forgiving and may still interpret multiple="true" as the attribute being present, relying on this behavior is fragile and non-standard.
- Accessibility: Assistive technologies rely on valid, well-structured markup. An invalid attribute value could lead to unpredictable behavior in screen readers or other tools.
- Maintainability: Using multiple on an unsupported input type suggests a misunderstanding of the element’s capabilities, which can confuse other developers and lead to bugs.
How to fix it
- Remove the value entirely: Change multiple="1" or multiple="true" to just multiple.
- Use a valid boolean syntax if a value is required: Some templating systems or XML-based contexts (like XHTML) require explicit attribute values. In those cases, use multiple="" or multiple="multiple".
- Ensure the input type supports multiple: Only type="email" and type="file" accept this attribute. If you need multi-value input for other types, consider alternative approaches like multiple separate inputs, a <select multiple> element, or a JavaScript-based solution.
Examples
Invalid: wrong value on a boolean attribute
<!-- Bad: "1" is not a valid boolean attribute value -->
<input type="file" name="attachments" multiple="1">
<!-- Bad: "true" is not a valid boolean attribute value -->
<input type="email" name="recipients" multiple="true">
Invalid: multiple on an unsupported input type
<!-- Bad: type="text" does not support the multiple attribute -->
<input type="text" name="tags" multiple>
<!-- Bad: type="number" does not support the multiple attribute -->
<input type="number" name="quantities" multiple>
Valid: correct usage of multiple
<!-- Correct: boolean attribute with no value -->
<input type="file" name="attachments" multiple>
<!-- Correct: empty string value (valid boolean syntax) -->
<input type="email" name="recipients" multiple="">
<!-- Correct: attribute name as value (valid for XHTML compatibility) -->
<input type="file" name="documents" multiple="multiple">
Full corrected document
<!DOCTYPE html>
<html lang="en">
<head>
<title>Upload Form</title>
</head>
<body>
<form action="/submit" method="post" enctype="multipart/form-data">
<label for="recipients">Recipients:</label>
<input type="email" id="recipients" name="recipients" multiple placeholder="a@example.com, b@example.com">
<label for="files">Attachments:</label>
<input type="file" id="files" name="files" multiple>
<button type="submit">Send</button>
</form>
</body>
</html>
An HTTP 202 Accepted status code indicates that the server has received and acknowledged the request, but the processing is not yet complete. This is commonly used for asynchronous operations — the server queues the work and responds immediately to let the client know the request was accepted without making the client wait. While this is perfectly valid for APIs and background job systems, it’s not appropriate for serving HTML documents, stylesheets, scripts, or other resources that the browser (or validator) needs to read immediately.
The W3C HTML Validator works by fetching your page and any linked resources (CSS files, images, scripts, etc.) over HTTP. It expects a 200 OK response with the full content in the response body. When it receives a 202 Accepted, the body may be empty, incomplete, or contain a placeholder — none of which can be meaningfully validated. This results in the validator aborting its check for that resource and reporting the error.
Common Causes
- Server-side processing delays: Your web server or application framework is deferring content generation to a background process and returning 202 as an interim response.
- Asynchronous or queued endpoints: The URL points to an API-style endpoint that triggers a job rather than serving content directly.
- CDN or proxy misconfiguration: A content delivery network or reverse proxy in front of your server is returning 202 while it fetches or generates the resource from the origin.
- On-demand static site generation: Some platforms generate pages on first request and return 202 until the build is complete (e.g., incremental static regeneration that hasn’t cached the page yet).
How to Fix
The core fix is ensuring that the URL you submit to the validator responds with a 200 OK status and delivers the full resource content in the response body. Here are specific steps:
-
Check your server configuration. Make sure your web server or application returns 200 OK for HTML pages and static assets. If background processing is needed, it should happen before the response is sent, or the result should be cached and served directly on subsequent requests.
-
Avoid validating asynchronous endpoints. If a URL is designed to trigger background work (like a webhook or task queue), it’s not a validatable HTML resource. Only submit URLs that serve complete HTML documents.
-
Pre-warm cached content. If your hosting platform uses on-demand generation, visit the URL in a browser first to trigger the build, then validate it once the page is fully generated and cached.
-
Inspect the response headers. Use browser developer tools or a command-line tool like curl -I <url> to verify the status code your server actually returns. Look for the HTTP/1.1 202 Accepted line and trace why it’s being sent.
Examples
Incorrect server behavior (returns 202)
In this conceptual example, the server responds with 202 for an HTML page, which prevents the validator from checking it:
HTTP/1.1 202 Accepted
Content-Type: text/html
<!-- Content may be empty or incomplete -->
If you’re using a Node.js/Express server, this kind of code would cause the problem:
app.get('/page', (req, res) => {
res.status(202).send('<p>Processing...</p>');
// Background work happens later
});
Correct server behavior (returns 200)
The server should respond with 200 OK and the complete HTML content:
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
<!DOCTYPE html>
<html lang="en">
<head>
<title>My Page</title>
</head>
<body>
<h1>Welcome</h1>
<p>This page is fully rendered and ready to validate.</p>
</body>
</html>
The equivalent fix in a Node.js/Express server:
app.get('/page', (req, res) => {
const html = renderPage(); // Generate full content synchronously or await it
res.status(200).send(html);
});
Verifying the status code with curl
You can check what status code a URL returns before submitting it to the validator:
curl -I https://example.com/page
Look for HTTP/1.1 200 OK (or HTTP/2 200) in the first line of the output. If you see 202 Accepted, investigate your server configuration before attempting validation.
The W3C HTML Validator doesn’t just parse your markup—it also attempts to retrieve external resources referenced in elements like <link>, <script>, <img>, and <iframe>. When a server returns a 403 status code, it’s telling the validator “you are not authorized to access this resource.” The validator then reports this as an informational message because it cannot fully validate the referenced content.
Common Causes
Several server-side configurations can trigger this issue:
- Hotlink protection — Many servers and CDNs block requests that don’t originate from an approved domain. Since the validator’s requests come from validator.w3.org, they get rejected.
- IP-based restrictions or firewalls — The remote server may restrict access to specific IP ranges, blocking the validator’s servers.
- User-Agent filtering — Some servers reject requests from bots or non-browser User-Agents, which includes the validator.
- Authentication requirements — The resource may sit behind a login wall or require API keys or tokens.
- Geographic restrictions — The server may use geo-blocking that prevents access from the validator’s location.
Why This Matters
While this is typically an informational warning rather than a hard HTML error, it has practical implications:
- Incomplete validation — The validator can’t check the referenced resource for errors. For example, if a CSS file returns 403, the validator can’t verify the stylesheet for issues that might affect your page.
- Potential broken references — A 403 may indicate that the resource URL is incorrect or outdated, meaning real users could also experience issues depending on their browser or network configuration.
- Accessibility and reliability concerns — If the resource is intermittently blocked, some users may not receive critical stylesheets or scripts, leading to a degraded experience.
How to Fix It
- Verify the URL is correct — Double-check for typos or outdated paths.
- Host resources on your own server — Download the resource and serve it locally or from a CDN you control.
- Use a CDN that permits open access — Popular open CDNs like cdnjs, jsDelivr, or unpkg are designed to allow unrestricted access.
- Configure the remote server — If you control the server hosting the resource, whitelist the validator’s User-Agent or allow requests from validator.w3.org.
- Remove unnecessary references — If the resource isn’t actually needed, remove the element entirely.
Examples
Resource blocked by remote server
This references a stylesheet on a server that returns 403 to the validator:
<link rel="stylesheet" href="https://restricted-server.example.com/styles/main.css">
Fixed: Host the resource locally
Download the stylesheet and serve it from your own domain:
<link rel="stylesheet" href="/css/main.css">
Fixed: Use a publicly accessible CDN
Switch to a well-known open CDN that doesn’t block external requests:
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
Script blocked by hotlink protection
<script src="https://protected-site.example.com/js/library.min.js"></script>
Fixed: Use a reliable public source
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
Image blocked by access restrictions
<img src="https://private-cdn.example.com/photos/banner.jpg" alt="Welcome banner">
Fixed: Host the image yourself
<img src="/images/banner.jpg" alt="Welcome banner">
Keep in mind that this warning only appears during validation—it doesn’t necessarily mean your end users are experiencing the same 403 error. Browsers send different headers (including cookies, referrers, and User-Agent strings) than the validator does, so the resource may load fine for visitors. However, it’s still good practice to ensure your referenced resources are reliably accessible and that validation can complete fully.
This error is not about your HTML syntax being invalid — it’s about a broken reference. The W3C Validator follows URLs it encounters in your markup (or a URL you submit directly for validation) and checks whether the server can actually deliver the resource. When the remote server returns an HTTP 404 (Not Found) response, the validator flags the issue because the referenced resource is missing or unreachable.
There are several common causes for this error:
- Typos in the URL — A misspelled filename, path, or domain name.
- Moved or deleted resources — The file existed at one point but has since been removed or relocated.
- Case sensitivity — Many web servers treat Image.png and image.png as different files. A mismatch in letter casing can produce a 404.
- Incorrect relative paths — A relative URL that resolves differently than expected based on the document’s location.
- External resources no longer available — Third-party CDNs or hosted files that have been taken down.
This matters because broken references degrade the user experience. Missing stylesheets can leave a page unstyled, missing scripts can break functionality, and missing images display broken image icons. Search engines also penalize pages with excessive broken links, and screen readers may announce confusing or unhelpful content when resources fail to load.
How to Fix It
- Check the URL carefully. Copy the full URL from your HTML, paste it into a browser, and see if it loads. If it returns a 404 page, the URL is wrong.
- Verify the file exists on the server. If you control the server, confirm the file is in the expected directory with the exact filename and extension.
- Fix case sensitivity issues. Ensure the capitalization in your URL matches the actual filename on the server.
- Update moved resources. If a file was relocated, update the href or src attribute to point to the new location.
- Replace unavailable external resources. If a third-party resource is no longer available, find an alternative source, host a copy yourself, or remove the reference.
Examples
Broken image reference (triggers the error)
<img src="https://example.com/images/photo.jpeg" alt="A scenic landscape">
If photo.jpeg doesn’t exist at that path (perhaps the actual file is named photo.jpg), the validator will report a 404 error.
Fixed image reference
<img src="https://example.com/images/photo.jpg" alt="A scenic landscape">
Broken stylesheet reference (triggers the error)
<link rel="stylesheet" href="/css/Styles.css">
If the file on the server is actually named styles.css (lowercase), a case-sensitive server will return a 404.
Fixed stylesheet reference
<link rel="stylesheet" href="/css/styles.css">
Broken script reference with incorrect path (triggers the error)
<script src="/assets/js/old-directory/app.js"></script>
If the script was moved to a different directory, this path no longer resolves.
Fixed script reference
<script src="/assets/js/app.js"></script>
Using a relative path incorrectly (triggers the error)
If your HTML file is at /pages/about.html and you reference an image like this:
<img src="images/logo.png" alt="Company logo">
The browser will look for /pages/images/logo.png. If the image actually lives at /images/logo.png, this will fail.
Fixed with a root-relative path
<img src="/images/logo.png" alt="Company logo">
The leading / ensures the path is resolved from the root of the site, regardless of where the HTML document is located.
HTTP status code 429 is defined in RFC 6585 and signals that a client has sent too many requests in a given time period. When the W3C Validator encounters your HTML, it doesn’t just parse the markup — it also attempts to retrieve linked resources like stylesheets, scripts, and images to perform thorough validation. If any of those resources are hosted on a server that enforces rate limits (which is common with CDNs, API providers, and popular hosting platforms), the server may reject the validator’s request with a 429 response.
This is not a syntax error in your HTML. Your markup may be perfectly valid. The issue is environmental: the remote server is temporarily refusing connections from the validator. However, because the validator cannot retrieve the resource, it cannot fully verify everything about your page, so it flags the problem.
Common Causes
- Rapid repeated validation: Running the validator many times in quick succession against pages that reference the same external resources.
- Shared rate limits: The W3C Validator service shares outbound IP addresses, so other users’ validation requests may count against the same rate limit on the remote server.
- Aggressive server-side rate limiting: The remote server or its CDN (e.g., Cloudflare, AWS CloudFront) has strict rate-limiting rules that block automated HTTP clients quickly.
- Many external resources: A page that references numerous resources from the same external host may trigger rate limits in a single validation pass.
How to Fix It
Wait and retry
Since 429 is a temporary condition, simply waiting a few minutes and revalidating is often enough. Some servers include a Retry-After header in the 429 response indicating how long to wait, though the validator may not surface this detail.
Reduce validation frequency
If you’re running automated validation (e.g., in a CI/CD pipeline), space out your requests. Avoid validating dozens of pages in rapid-fire succession.
Host resources locally
If you control the website, consider self-hosting critical resources rather than relying on third-party CDNs. This gives you full control over availability and eliminates third-party rate-limit issues during validation.
Adjust server rate limits
If you own the server that’s returning 429, review your rate-limiting configuration. You may want to whitelist the W3C Validator’s user agent or IP range, or relax limits that are overly aggressive for legitimate automated tools.
Examples
Page that may trigger the issue
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>My Page</title>
<link rel="stylesheet" href="https://cdn.example.com/styles/main.css">
<script src="https://cdn.example.com/scripts/app.js"></script>
</head>
<body>
<h1>Hello, world!</h1>
</body>
</html>
If cdn.example.com rate-limits the validator, both the stylesheet and script fetches could fail with a 429, producing two “HTTP resource not retrievable” messages.
Fix: Self-host the resources
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>My Page</title>
<link rel="stylesheet" href="/css/main.css">
<script src="/js/app.js"></script>
</head>
<body>
<h1>Hello, world!</h1>
</body>
</html>
By serving main.css and app.js from your own domain, you eliminate the dependency on a third-party server’s rate limits during validation.
Fix: Reduce external dependencies
If self-hosting isn’t feasible, minimize the number of external resources from a single host to lower the chance of hitting rate limits:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>My Page</title>
<link rel="stylesheet" href="https://cdn.example.com/bundle.css">
</head>
<body>
<h1>Hello, world!</h1>
<script src="https://cdn.example.com/bundle.js"></script>
</body>
</html>
Bundling multiple files into single resources reduces the total number of requests the validator needs to make to the external server, making rate-limit errors less likely.
When the W3C Validator encounters a URL in your HTML — whether in a <link>, <script>, <img>, or any other element that references an external resource — it may attempt to retrieve that resource as part of the validation process. If the remote server returns an HTTP 503 status code, the validator cannot fetch the resource and raises this error. The 503 status code specifically means “Service Unavailable,” indicating a temporary condition on the server side.
This error is not a problem with your HTML syntax. It’s an infrastructure issue that can be caused by several factors:
- Server maintenance: The remote server is temporarily down for updates or scheduled maintenance.
- Server overload: The server is handling too many requests and cannot respond in time.
- Rate limiting: Some servers detect automated requests (like those from the validator) and respond with 503 to throttle traffic.
- CDN or hosting issues: The content delivery network or hosting provider is experiencing temporary problems.
- Incorrect URL: The resource URL may point to a server that no longer hosts the expected content.
While this isn’t a standards compliance issue per se, it’s important to address because unreachable resources can affect your page’s rendering, functionality, and accessibility. A missing stylesheet means unstyled content, a missing script means broken interactivity, and a missing image means absent visual information.
How to Fix It
- Verify the URL: Open the referenced URL directly in a browser to confirm it’s valid and accessible.
- Retry later: Since 503 is a temporary status, simply re-running the validator after some time often resolves the issue.
- Host resources locally: For critical assets like stylesheets and scripts, consider self-hosting them rather than relying on third-party servers.
- Use reliable CDNs: If you use a CDN, choose one with high uptime guarantees (e.g., established providers for popular libraries).
- Add fallbacks: For scripts loaded from external CDNs, consider including a local fallback.
Examples
External resource that may trigger a 503
<link rel="stylesheet" href="https://example.com/styles/main.css">
<script src="https://example.com/libs/library.js"></script>
If example.com is temporarily unavailable, the validator will report the 503 error for each of these resources.
Fix: Host resources locally
<link rel="stylesheet" href="/css/main.css">
<script src="/js/library.js"></script>
By hosting the files on your own server, you eliminate the dependency on a third-party server’s availability and ensure the validator (and your users) can always access them.
Fix: Use a reliable CDN with a local fallback
<script src="https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js"></script>
<script>
if (typeof jQuery === "undefined") {
var s = document.createElement("script");
s.src = "/js/jquery.min.js";
document.head.appendChild(s);
}
</script>
This approach loads jQuery from a well-known CDN but falls back to a local copy if the CDN is unavailable. While this fallback pattern doesn’t prevent the validator warning itself, it ensures your page works for real users even when the CDN is down.
Fix: Validate using “text input” mode
If the 503 errors persist and are caused by the validator’s requests being blocked or rate-limited, you can work around the issue by validating your HTML using the validator’s “Validate by Direct Input” option. Paste your HTML source code directly into the validator at https://validator.w3.org/#validate_by_input. This still validates your markup structure and syntax, though the validator may not check externally referenced resources.
Keep in mind that a 503 error during validation is almost always temporary. If you’ve confirmed your URLs are correct and the resources load fine in a browser, the safest approach is simply to wait and validate again later.
The doctype declaration tells browsers which version of HTML a page uses and, critically, determines whether the browser renders the page in standards mode or quirks mode. Standards mode follows current CSS and HTML specifications, while quirks mode emulates the buggy behavior of older browsers from the late 1990s and early 2000s. When the W3C validator reports “Quirky doctype,” it means your document’s doctype is one that is known to trigger quirks mode—and in the context of modern HTML, this is always undesirable.
Several legacy doctypes can trigger this warning, including:
- <!DOCTYPE html public "-//W3C//DTD HTML 4.0 Transitional//EN"> (without a system identifier URL)
- <!DOCTYPE html public "-//W3C//DTD HTML 3.2 Final//EN">
- Malformed or incomplete doctype declarations
- Doctypes with unexpected casing or extra whitespace in certain positions
The HTML Living Standard (maintained by WHATWG) specifies that the doctype must be <!DOCTYPE html>. This short declaration is case-insensitive but is conventionally written in uppercase. It exists solely to trigger standards mode—it does not reference a DTD because HTML5 is not based on SGML.
Why This Matters
Inconsistent rendering: In quirks mode, browsers alter how they calculate the box model, handle table sizing, apply inline element dimensions, and more. A page that looks correct in one browser may break in another because each browser’s quirks mode emulates different legacy behaviors.
Accessibility and interoperability: Screen readers and other assistive technologies rely on predictable DOM behavior. Quirks mode can cause unexpected layout shifts and content reflow that degrade the experience for users of assistive technology.
Standards compliance: Modern HTML validators expect the HTML5 doctype. Using a legacy doctype signals that the document is not following current web standards, which can also affect SEO tools and automated audits.
How to Fix It
- Open your HTML file and locate the very first line.
- Replace whatever doctype declaration is there with <!DOCTYPE html>.
- Ensure nothing appears before the doctype—no whitespace, no comments, no byte order marks (BOMs). Any content before the doctype can also trigger quirks mode in some browsers.
- Verify that the rest of your document uses valid HTML5 syntax (e.g., the <html> tag includes a lang attribute, the <head> contains a <meta charset> declaration and a <title> element).
Examples
Incorrect: Legacy doctype triggering quirks mode
<!DOCTYPE html public "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>My Page</title>
</head>
<body>
<p>This page renders in quirks mode.</p>
</body>
</html>
This HTML 4.0 Transitional doctype without a system identifier URL is a known quirks-mode trigger.
Incorrect: Another common quirky doctype
<!DOCTYPE html public "-//W3C//DTD HTML 3.2 Final//EN">
<html>
<head>
<title>My Page</title>
</head>
<body>
<p>This older doctype also triggers quirks mode.</p>
</body>
</html>
Correct: Standard HTML5 doctype
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>My Page</title>
</head>
<body>
<p>This page renders in standards mode.</p>
</body>
</html>
The simple <!DOCTYPE html> declaration ensures standards mode across all modern browsers. It is the only doctype you should use for new HTML documents, and it is also fully backward-compatible with older browsers—even Internet Explorer 6 renders in standards mode with this doctype.
The <html> element serves as the root of an HTML document. According to the HTML specification, there can only be one root element, and it must contain exactly one <head> element followed by one <body> element. When the browser’s parser encounters a second <html> start tag, it doesn’t know what to do with it — the tag is considered “stray” because it appears in a context where it is not expected or allowed.
This error typically occurs in a few common scenarios:
- Copy-paste mistakes — When copying HTML from another file, you may accidentally paste an entire document (including its <html> tag) inside an existing document.
- Template or include errors — Server-side includes, template engines, or component-based frameworks may inject a full HTML document structure (with its own <html> tag) into a page that already has one.
- Merging files incorrectly — Combining multiple HTML files without removing the structural tags from the inner files.
- Accidental duplication — Simply having a duplicate <html> tag due to a typo or editing oversight.
A stray <html> tag signals a malformed document structure. Browsers will attempt to recover by ignoring the duplicate tag, but the intent behind the markup becomes ambiguous. This can lead to unpredictable rendering, broken styles, or scripts that fail to target elements correctly. It also harms accessibility, as screen readers and other assistive technologies rely on a well-formed document tree to interpret content.
To fix this issue, search your HTML source for all instances of <html and ensure only one exists — at the very top of the document, right after the <!DOCTYPE html> declaration. If you find a second one, remove it along with any corresponding duplicate </html>, <head>, </head>, <body>, and </body> tags that came with it, keeping only the actual content you need.
Examples
Incorrect: Duplicate <html> tag from pasted content
This example shows a full HTML document accidentally embedded inside another, which produces the stray start tag error:
<!DOCTYPE html>
<html lang="en">
<head>
<title>My Page</title>
</head>
<body>
<h1>Welcome</h1>
<!-- Accidentally pasted another full document -->
<!DOCTYPE html>
<html lang="en">
<head>
<title>Other Page</title>
</head>
<body>
<p>This content was pasted from another file.</p>
</body>
</html>
</body>
</html>
Correct: Single <html> element with merged content
Remove the duplicate document structure and keep only the content you need:
<!DOCTYPE html>
<html lang="en">
<head>
<title>My Page</title>
</head>
<body>
<h1>Welcome</h1>
<!-- Only the relevant content from the other file -->
<p>This content was pasted from another file.</p>
</body>
</html>
Incorrect: Accidental duplicate <html> tag
Sometimes the duplication is a simple typo:
<!DOCTYPE html>
<html lang="en">
<html lang="en">
<head>
<title>My Page</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
Correct: Single <html> tag
<!DOCTYPE html>
<html lang="en">
<head>
<title>My Page</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
Checking template-based projects
If you use a templating system (e.g., PHP includes, Jinja2, Handlebars, or similar), make sure your partials and includes contain only content fragments — not full document structures. For example, an included partial should look like this:
<!-- partial: sidebar.html — no <html>, <head>, or <body> tags -->
<aside>
<nav>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
</ul>
</nav>
</aside>
The key rule is simple: every HTML document must have exactly one <html> element. If the validator reports a stray start tag, trace it back to its source — whether that’s a copy-paste error, a template include, or a simple duplication — and remove it.
In earlier versions of HTML, the version attribute on the <html> element served as a way to indicate the DTD (Document Type Definition) the document followed. For example, you might have seen something like <html version="-//W3C//DTD HTML 4.01//EN">. This was largely redundant even then, because the <!DOCTYPE> declaration at the top of the document already communicated the same information to browsers and validators.
With the introduction of HTML5, the version attribute was officially marked as obsolete. The HTML Living Standard maintained by WHATWG does not define or support it. Modern browsers completely ignore it, so it has no functional effect on rendering or behavior. However, keeping it in your markup produces a validation warning from the W3C HTML Validator and adds unnecessary clutter to your code.
Removing this attribute has no side effects. The <!DOCTYPE html> declaration is the only mechanism needed to signal that your document uses the current HTML standard. Keeping your markup clean and free of obsolete attributes improves maintainability and ensures your documents pass validation without unnecessary warnings.
How to fix it
- Locate the <html> tag in your document.
- Remove the version attribute and its value entirely.
- Ensure you have a valid <!DOCTYPE html> declaration at the top of the document.
- Keep the lang attribute on the <html> element, as it is important for accessibility and internationalization.
Examples
Incorrect: using the obsolete version attribute
<!DOCTYPE html>
<html version="-//W3C//DTD HTML 4.01//EN" lang="en">
<head>
<title>My Page</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
This triggers the W3C validator warning: The “version” attribute on the “html” element is obsolete.
Correct: version attribute removed
<!DOCTYPE html>
<html lang="en">
<head>
<title>My Page</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
The version attribute has been removed, and the document remains fully valid. The <!DOCTYPE html> declaration and the lang attribute are the only things needed on the <html> element for a well-formed, standards-compliant document.
Ready to validate your sites?
Start your free trial today.