HTML Guides
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 space character in the fragment portion of a URL (the part after #) is not allowed in the src attribute of an img element.
URLs follow the syntax defined in RFC 3986, which does not permit literal spaces anywhere in the URI, including the fragment identifier. Browsers may silently handle spaces by percent-encoding them, but the raw HTML remains invalid. The W3C validator flags this because the src value must be a valid URL before the browser ever processes it.
To fix the issue, replace each space in the URL with %20, which is the percent-encoded form of a space character. This applies to all parts of the URL: the path, query string, and fragment.
A common cause is copying a URL from a browser address bar or a document system where filenames or anchors contain spaces. Another cause is linking to a named anchor (id) on a page where the id value itself contains a space, which is also invalid HTML — id values must not contain spaces.
HTML examples
Invalid: space in fragment
<img src="diagram.svg#my section" alt="Diagram of section layout">
Valid: percent-encoded space
<img src="diagram.svg#my%20section" alt="Diagram of section layout">
If you control the target resource, a better fix is to remove the space from the fragment identifier entirely:
<img src="diagram.svg#my-section" alt="Diagram of section layout">
Using hyphens or underscores instead of spaces in fragment identifiers and file names avoids this class of problem altogether.
The URL specification (defined by WHATWG and RFC 3986) restricts which characters can appear unencoded in different parts of a URL. Square brackets are reserved characters that have a specific meaning in URLs — they are only permitted in the host portion (to wrap IPv6 addresses like [::1]). In the query string, they must be percent-encoded.
This issue commonly appears when frameworks (especially PHP, Ruby on Rails, or JavaScript libraries) generate URLs with array-style query parameters like ?filter[color]=red. While many browsers and servers are lenient and will interpret these URLs correctly, they are technically invalid according to the URL standard. The W3C validator enforces this rule strictly.
Beyond standards compliance, using unencoded square brackets can cause problems in practice. Some HTTP clients, proxies, or caching layers may reject or mangle URLs containing raw brackets. Percent-encoding these characters ensures your URLs are universally safe and interoperable across all systems.
How to fix it
You have two main approaches:
Percent-encode the brackets. Replace every
[with%5Band every]with%5Din the URL. This preserves the parameter structure that your server or framework expects, while making the URL valid.Restructure the query parameters. If your backend allows it, use flat parameter names with dot notation, underscores, or dashes instead of bracket syntax. For example, change
size[width]tosize_widthorsize.width.
If you're generating URLs in JavaScript, the built-in encodeURI() function does not encode square brackets. Use encodeURIComponent() on individual parameter names or values, or manually replace [ and ] after constructing the URL.
Examples
❌ Invalid: unencoded square brackets in query string
<img src="/images/photo.jpg?size[width]=300&size[height]=200" alt="A sample photo">
The literal [ and ] characters in the query string trigger the validation error.
✅ Fixed: percent-encoded brackets
<img src="/images/photo.jpg?size%5Bwidth%5D=300&size%5Bheight%5D=200" alt="A sample photo">
Replacing [ with %5B and ] with %5D makes the URL valid. Most servers and frameworks will decode these automatically and interpret the parameters the same way.
✅ Fixed: flat parameter names without brackets
<img src="/images/photo.jpg?size_width=300&size_height=200" alt="A sample photo">
If you control the server-side logic, you can avoid brackets altogether by using a flat naming convention for your parameters.
❌ Invalid: brackets in more complex query strings
<img
src="/api/image?filters[type]=jpeg&filters[quality]=80&crop[x]=10&crop[y]=20"
alt="Processed image">
✅ Fixed: all brackets encoded
<img
src="/api/image?filters%5Btype%5D=jpeg&filters%5Bquality%5D=80&crop%5Bx%5D=10&crop%5By%5D=20"
alt="Processed image">
Encoding in JavaScript
If you build image URLs dynamically, handle the encoding in your code:
// Manual replacement approach
const url = "/images/photo.jpg?size[width]=300&size[height]=200";
const safeUrl = url.replace(/\[/g, "%5B").replace(/\]/g, "%5D");
img.src = safeUrl;
// Using URLSearchParams (automatically encodes brackets)
const params = new URLSearchParams();
params.set("size[width]", "300");
params.set("size[height]", "200");
img.src = `/images/photo.jpg?${params.toString()}`;
Both approaches produce a valid, properly encoded URL that will pass W3C validation.
The W3C HTML validator raises this error when the src attribute of an <img> element contains characters that are not permitted in a valid URI. The most common culprit is the < character, but other characters like >, {, }, |, \, ^, and backticks are also illegal in URIs according to RFC 3986.
This issue typically occurs in a few common scenarios:
- Template syntax left unresolved: Server-side or client-side template tags (e.g.,
<%= imageUrl %>,{{ image.src }}) appear literally in the HTML output instead of being processed into actual URLs. - Copy-paste errors: HTML markup or angle brackets accidentally end up inside a
srcvalue. - Malformed dynamic URLs: JavaScript or server-side code incorrectly constructs a URL that includes raw HTML or special characters.
This matters because browsers may fail to load the image or interpret the URL unpredictably. Invalid URIs can also cause issues with screen readers and assistive technologies that try to resolve the src to provide context about the image. Keeping your markup standards-compliant ensures consistent behavior across all browsers and environments.
How to fix it
- Check for unprocessed template tags. If you see template syntax like
<%,{{, or similar in the rendered HTML, ensure your templating engine is running correctly and outputting the resolved URL. - Use valid, well-formed URLs. The
srcvalue should be a properly formatted absolute or relative URL. - Percent-encode special characters. If a special character is genuinely part of the URL (which is rare for
<), encode it:<becomes%3C,>becomes%3E, and so on. - Inspect your generated HTML. View the page source in your browser to confirm the actual output, rather than relying on what your code looks like before processing.
Examples
Incorrect — template syntax in src
The template tag was not processed, leaving a < character in the src attribute:
<img src="<%= user.avatar %>" alt="User avatar">
Incorrect — HTML accidentally inside src
Angle brackets from stray markup ended up in the URL:
<img src="images/<thumbnail>/photo.jpg" alt="Photo">
Correct — a valid relative URL
<img src="images/photo.jpg" alt="Photo">
Correct — a valid absolute URL
<img src="https://example.com/images/photo.jpg" alt="Photo">
Correct — special characters percent-encoded
If the URL genuinely requires characters that are not allowed in a URI, percent-encode them:
<img src="https://example.com/search?q=a%3Cb" alt="Search result">
In this case, %3C represents the < character in the query string, making the URI valid.
The HTML specification requires the src attribute of an <img> element to be a valid, non-empty URL. When you set src="", the browser has no resource to fetch, but many browsers will still attempt to make a request — often resolving the empty string relative to the current page URL. This means the browser may re-request the current HTML document as if it were an image, wasting bandwidth and potentially causing unexpected server-side behavior.
Beyond the technical waste, an empty src is problematic for accessibility. Screen readers rely on the <img> element to convey meaningful content. An image with no source provides no value and can confuse assistive technology users. Search engine crawlers may also flag this as a broken resource, negatively affecting SEO.
This issue commonly arises in a few scenarios:
- Placeholder images — developers leave
srcempty intending to set it later via JavaScript. - Template rendering — a server-side template or frontend framework outputs an
<img>tag before the image URL is available. - Lazy loading implementations — the real source is stored in a
data-srcattribute whilesrcis left empty.
How to fix it
The simplest fix is to provide a valid image URL in the src attribute. If the image source isn't available yet, consider these alternatives:
- Don't render the
<img>element at all until a valid source is available. - Use a small placeholder image (such as a transparent 1×1 pixel GIF or a lightweight SVG) as a temporary
src. - Use native lazy loading with
loading="lazy"and a realsrc, letting the browser handle deferred loading instead of relying on an emptysrc.
Examples
❌ Bad: empty src attribute
<img src="" alt="Profile photo">
This triggers the validation error because the src value is an empty string.
❌ Bad: src with only whitespace
<img src=" " alt="Profile photo">
Whitespace-only values are also considered invalid and will produce a similar error.
✅ Good: valid image path
<img src="photo.jpg" alt="Profile photo">
✅ Good: placeholder image for lazy loading
If you're implementing lazy loading and need a lightweight placeholder, use a small inline data URI or a real placeholder file:
<img
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
data-src="photo.jpg"
alt="Profile photo">
✅ Good: native lazy loading with a real src
Modern browsers support the loading attribute, eliminating the need for an empty src workaround:
<img src="photo.jpg" alt="Profile photo" loading="lazy">
✅ Good: conditionally render the element
If the image URL might not be available, avoid rendering the <img> tag entirely. For example, in a template:
<!-- Only include the img element when a source exists -->
<img src="photo.jpg" alt="Profile photo">
In frameworks like React, Vue, or server-side templating engines, use conditional logic to skip the <img> element when the URL is empty rather than outputting a tag with an empty src.
The src attribute on a <script> element tells the browser where to fetch an external JavaScript file. According to the HTML specification, when the src attribute is present, its value must be a valid non-empty URL. An empty string does not qualify as a valid URL, so the validator flags it as an error.
This issue typically arises in a few common scenarios:
- Templating or CMS placeholders — A template engine or content management system outputs an empty
srcwhen no script URL is configured. - Dynamic JavaScript — Client-side code is intended to set the
srclater, but the initial HTML ships with an empty value. - Copy-paste mistakes — The attribute was added in anticipation of a script file that was never specified.
Beyond failing validation, an empty src causes real problems. Most browsers interpret an empty src as a relative URL that resolves to the current page's URL. This means the browser will make an additional HTTP request to re-fetch the current HTML document and attempt to parse it as JavaScript, wasting bandwidth, slowing down page load, and potentially generating console errors. It can also cause unexpected side effects in server logs and analytics.
How to Fix It
Choose the approach that matches your intent:
- Provide a valid URL — If you need an external script, set
srcto the correct file path or full URL. - Use an inline script — If your JavaScript is written directly in the HTML, remove the
srcattribute entirely. Note that whensrcis present, browsers ignore any content between the opening and closing<script>tags. - Remove the element — If the script isn't needed, remove the
<script>element altogether.
Also keep in mind:
- Ensure the file path is correct relative to the HTML file's location.
- If using an absolute URL, verify it is accessible and returns JavaScript content.
- If a script should only be loaded conditionally, handle the condition in your server-side or build logic rather than outputting an empty
src.
Examples
❌ Invalid: Empty src attribute
<script src=""></script>
This triggers the validation error because the src value is an empty string.
❌ Invalid: Whitespace-only src attribute
<script src=" "></script>
A value containing only whitespace is also not a valid URL and will produce the same error.
✅ Fixed: Valid external script
<script src="js/app.js"></script>
The src attribute contains a valid relative URL pointing to an actual JavaScript file.
✅ Fixed: Valid external script with a full URL
<script src="https://example.com/js/library.min.js"></script>
✅ Fixed: Inline script without src
If you want to write JavaScript directly in your HTML, omit the src attribute:
<script>
console.log("This is an inline script.");
</script>
✅ Fixed: Conditionally omitting the element
If the script URL comes from a template variable that might be empty, handle it at the template level so the <script> element is only rendered when a URL is available. For example, in a templating language:
<!-- Pseudocode — only output the tag when the URL exists -->
<!-- {% if script_url %} -->
<script src="analytics.js"></script>
<!-- {% endif %} -->
This prevents the empty src from ever reaching the browser.
The <source> element is used inside <video>, <audio>, and <picture> elements to specify one or more media resources for the browser to choose from. Its src attribute is defined as a valid non-empty URL, meaning it must resolve to an actual file path or web address. An empty string does not satisfy this requirement and violates the HTML specification.
Why this is a problem
Standards compliance: The WHATWG HTML living standard explicitly requires the src attribute on <source> to be a non-empty, valid URL. An empty value makes the document invalid HTML.
Unexpected browser behavior: When a browser encounters an empty src, it may attempt to resolve it relative to the current page URL. This can trigger an unnecessary HTTP request back to the current page, resulting in wasted bandwidth, unexpected server load, or confusing errors in your network logs.
Broken media playback: An empty src means the browser has no media file to load. If the <source> element is the only one provided, the media element will fail to play entirely — often without a clear indication to the user of what went wrong.
Accessibility concerns: Screen readers and assistive technologies rely on well-formed HTML. Invalid markup can lead to unpredictable behavior or missed content announcements for users who depend on these tools.
How to fix it
- Provide a valid URL — Set the
srcattribute to the correct path or URL of your media file. - Remove the element — If the media source is not yet available or is being set dynamically via JavaScript, remove the
<source>element from the HTML entirely and add it later through script when the URL is known. - Check for template or CMS issues — This error often appears when a CMS or templating engine outputs a
<source>tag with an empty variable. Ensure your template conditionally renders the element only when a valid URL exists.
Examples
Incorrect: empty src on <source> in a video
<video controls>
<source src="" type="video/mp4">
Your browser does not support the video tag.
</video>
Correct: valid URL in src
<video controls>
<source src="movie.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
Incorrect: empty src on <source> in a picture element
<picture>
<source src="" type="image/webp">
<img src="photo.jpg" alt="A sunset over the ocean">
</picture>
Note that <source> inside <picture> uses srcset, not src. This example is doubly wrong — the attribute is both empty and incorrect. Here is the fix:
Correct: using srcset with a valid URL in a picture element
<picture>
<source srcset="photo.webp" type="image/webp">
<img src="photo.jpg" alt="A sunset over the ocean">
</picture>
Incorrect: multiple sources with one empty src
<audio controls>
<source src="song.ogg" type="audio/ogg">
<source src="" type="audio/mpeg">
</audio>
Correct: remove the source if no file is available
<audio controls>
<source src="song.ogg" type="audio/ogg">
<source src="song.mp3" type="audio/mpeg">
</audio>
Correct: conditionally add sources with JavaScript
If the URL is determined at runtime, avoid placing an empty <source> in your markup. Instead, add it dynamically:
<video id="player" controls>
Your browser does not support the video tag.
</video>
<script>
const videoUrl = getVideoUrl(); // your logic here
if (videoUrl) {
const source = document.createElement("source");
source.src = videoUrl;
source.type = "video/mp4";
document.getElementById("player").appendChild(source);
}
</script>
This approach keeps your HTML valid at all times and only inserts a <source> element when a real URL is available.
The srcset attribute on img and source elements accepts a comma-separated list of image candidate strings. Each candidate consists of a URL optionally followed by a width descriptor (e.g., 300w) or a pixel density descriptor (e.g., 2x). The URL in each candidate must conform to the URL Standard, which does not permit raw square brackets in the query string of an HTTP or HTTPS URL.
This issue commonly arises when a backend framework or CMS generates URLs that use square brackets in query parameters — for example, ?filter[size]=large or ?dimensions[]=300. While many browsers are lenient and will load these URLs anyway, they are technically invalid according to the URL specification. Using invalid URLs can lead to unpredictable behavior across different browsers, HTML parsers, and tools that process your markup. It also means your HTML fails W3C validation, which can mask other, more critical issues in your code.
You have two main approaches to fix this:
Percent-encode the brackets. Replace every
[with%5Band every]with%5D. This preserves the intended query parameter structure while making the URL spec-compliant. Your server should interpret percent-encoded brackets identically to raw brackets.Eliminate brackets from the URL. If you control the server-side code, consider using alternative query parameter conventions that don't rely on brackets — for instance, using dot notation (
filter.size=large), comma-separated values (dimensions=300,400), or repeated parameter names (dimension=300&dimension=400).
When fixing these URLs, also make sure each image candidate follows the correct format: a valid URL, followed by optional whitespace and a descriptor, with candidates separated by commas.
Examples
Incorrect — raw square brackets in query string
This triggers the validation error because [ and ] appear unescaped in the srcset URLs:
<img
src="photo.jpg"
srcset="photo.jpg?crop[width]=400 400w, photo.jpg?crop[width]=800 800w"
sizes="(max-width: 600px) 400px, 800px"
alt="A landscape photo">
Fixed — percent-encoded brackets
Replacing [ with %5B and ] with %5D makes the URLs valid:
<img
src="photo.jpg"
srcset="photo.jpg?crop%5Bwidth%5D=400 400w, photo.jpg?crop%5Bwidth%5D=800 800w"
sizes="(max-width: 600px) 400px, 800px"
alt="A landscape photo">
Fixed — brackets removed from URL design
If you can modify the server-side routing, restructuring the query parameters avoids the issue entirely:
<img
src="photo.jpg"
srcset="photo.jpg?crop_width=400 400w, photo.jpg?crop_width=800 800w"
sizes="(max-width: 600px) 400px, 800px"
alt="A landscape photo">
Incorrect — brackets with pixel density descriptors
The same problem occurs regardless of whether you use width descriptors or density descriptors:
<img
src="avatar.jpg"
srcset="avatar.jpg?size=[sm] 1x, avatar.jpg?size=[lg] 2x"
alt="User avatar">
Fixed — percent-encoded version
<img
src="avatar.jpg"
srcset="avatar.jpg?size=%5Bsm%5D 1x, avatar.jpg?size=%5Blg%5D 2x"
alt="User avatar">
Fixed — simplified query parameters
<img
src="avatar.jpg"
srcset="avatar.jpg?size=sm 1x, avatar.jpg?size=lg 2x"
alt="User avatar">
An srcset attribute must not end with a trailing comma, as each entry must be a complete image candidate string with a URL and an optional width or pixel density descriptor.
The srcset attribute accepts a comma-separated list of image candidate strings. Each string contains a URL and, optionally, a width descriptor (like 400w) or a pixel density descriptor (like 2x). A trailing comma after the last entry creates an empty image candidate string, which is invalid.
This error often appears when srcset values are built dynamically by a template engine or CMS that appends a comma after every item, including the last one.
Invalid example
<img
srcset="image-small.jpg 400w,
image-medium.jpg 800w,
image-large.jpg 1200w,"
sizes="(max-width: 800px) 400px, 800px"
src="image-medium.jpg"
alt="A sample photo"
>
The trailing comma after image-large.jpg 1200w, produces the validation error.
Fixed example
<img
srcset="image-small.jpg 400w,
image-medium.jpg 800w,
image-large.jpg 1200w"
sizes="(max-width: 800px) 400px, 800px"
src="image-medium.jpg"
alt="A sample photo"
>
Removing the trailing comma after the last image candidate string fixes the issue.
The srcset attribute allows you to provide multiple image sources so the browser can choose the most appropriate one based on the user's device and viewport. There are two distinct modes for srcset:
- Width descriptor mode — Each candidate specifies the image's intrinsic width using a
wdescriptor (e.g.,640w). This mode requires thesizesattribute so the browser knows how much space the image will occupy in the layout, enabling it to pick the best candidate. - Density descriptor mode — Each candidate specifies a pixel density using an
xdescriptor (e.g.,2x). This mode does not use thesizesattribute; the browser simply matches candidates to the device's pixel density.
These two modes are mutually exclusive. You cannot mix w and x descriptors in the same srcset, and you cannot use x descriptors (or bare URLs with no descriptor) when sizes is present. The HTML specification is explicit about this: if sizes is specified, all image candidate strings must include a width descriptor.
Why this matters
- Standards compliance: The WHATWG HTML Living Standard defines strict parsing rules for
srcset. Whensizesis present, the browser's source selection algorithm expects width descriptors. Providing density descriptors or bare candidates in this context violates the spec and produces undefined behavior. - Broken image selection: Browsers rely on the
sizesattribute to calculate whichw-described image best fits the current layout width. If you providexdescriptors alongsidesizes, the browser may ignore thesrcsetentirely or fall back to thesrcattribute, defeating the purpose of responsive images. - Accessibility and performance: Responsive images exist to serve appropriately sized files to different devices. An invalid
srcset/sizescombination can result in oversized images being downloaded on small screens (wasting bandwidth) or undersized images on large screens (reducing visual quality).
How to fix it
You have two options:
- Keep
sizesand switch to width descriptors — Replace everyxdescriptor (or missing descriptor) insrcsetwith the actual intrinsic pixel width of each image file, expressed with awsuffix. - Remove
sizesand keep density descriptors — If you only need to serve different resolutions for high-DPI screens at a fixed layout size, drop thesizesattribute and usexdescriptors.
When using width descriptors, the value must match the image file's actual intrinsic width in pixels. For example, if photo-640.jpg is 640 pixels wide, its descriptor should be 640w.
Examples
Invalid: sizes present with density descriptors
This triggers the error because 1x and 2x are density descriptors, but sizes requires width descriptors.
<img
src="photo-640.jpg"
srcset="photo-640.jpg 1x, photo-1280.jpg 2x"
sizes="(max-width: 600px) 100vw, 600px"
alt="A mountain landscape">
Invalid: sizes present with a bare candidate (no descriptor)
A candidate with no descriptor defaults to 1x, which is a density descriptor — still invalid when sizes is present.
<img
src="photo-640.jpg"
srcset="photo-640.jpg, photo-1280.jpg 2x"
sizes="(max-width: 600px) 100vw, 600px"
alt="A mountain landscape">
Fix: use width descriptors with sizes
Each candidate now specifies the intrinsic width of the image file. The browser uses the sizes value to determine which image to download.
<img
src="photo-640.jpg"
srcset="photo-320.jpg 320w, photo-640.jpg 640w, photo-1280.jpg 1280w"
sizes="(max-width: 600px) 100vw, 600px"
alt="A mountain landscape">
Alternative fix: remove sizes and use density descriptors
If you don't need the browser to choose images based on layout width — for example, the image always renders at a fixed CSS size — drop sizes and use x descriptors.
<img
src="photo-640.jpg"
srcset="photo-640.jpg 1x, photo-1280.jpg 2x"
alt="A mountain landscape">
Using width descriptors with source inside picture
The same rule applies to source elements inside a picture. If sizes is present, every candidate must use a w descriptor.
<picture>
<source
srcset="hero-480.webp 480w, hero-960.webp 960w, hero-1920.webp 1920w"
sizes="(max-width: 768px) 100vw, 50vw"
type="image/webp">
<img
src="hero-960.jpg"
srcset="hero-480.jpg 480w, hero-960.jpg 960w, hero-1920.jpg 1920w"
sizes="(max-width: 768px) 100vw, 50vw"
alt="A hero banner image">
</picture>
When an img element has a sizes attribute, every image candidate in the srcset attribute must include a width descriptor (like 480w), not a pixel density descriptor (like 2x) or a bare URL.
The srcset attribute accepts two types of descriptors, but they cannot be mixed, and the choice depends on whether sizes is present.
Width descriptors (w) tell the browser the actual pixel width of each source image. The browser then uses the sizes attribute to determine how much space the image will occupy in the layout and picks the best candidate from srcset. This pairing of srcset with width descriptors and sizes is how responsive image selection works.
Pixel density descriptors (x) tell the browser which image to use based on the device's pixel density (e.g., 1x for standard screens, 2x for retina). When using density descriptors, the sizes attribute has no role and should be omitted.
The validation error appears when sizes is present but one or more entries in srcset lack a w descriptor. A bare URL with no descriptor is treated as 1x by default, which conflicts with the requirement that sizes demands width descriptors.
Invalid example
<img
src="photo-800.jpg"
srcset="photo-400.jpg, photo-800.jpg 2x"
sizes="(max-width: 600px) 100vw, 50vw"
alt="A landscape photo">
Here, photo-400.jpg has no descriptor (defaults to 1x), and photo-800.jpg uses 2x. Because sizes is present, the validator expects every candidate to specify a width.
Fixed example
<img
src="photo-800.jpg"
srcset="photo-400.jpg 400w, photo-800.jpg 800w"
sizes="(max-width: 600px) 100vw, 50vw"
alt="A landscape photo">
Each candidate now includes a width descriptor that reflects the image's intrinsic width in pixels. The browser compares these widths against the resolved sizes value to choose the most appropriate source.
If you do not need sizes and just want to serve different images for different pixel densities, drop the sizes attribute and use density descriptors instead:
<img
src="photo-400.jpg"
srcset="photo-400.jpg 1x, photo-800.jpg 2x"
alt="A landscape photo">
The srcset attribute supports two types of descriptors: width descriptors (like 480w) and pixel density descriptors (like 2x). However, these two types cannot be mixed, and the sizes attribute is only compatible with width descriptors. The sizes attribute tells the browser how wide the image will be displayed at various viewport sizes, and the browser uses this information along with the width descriptors in srcset to choose the most appropriate image file. If sizes is present but an image candidate lacks a width descriptor, the browser cannot perform this calculation correctly.
This matters for several reasons. First, it violates the WHATWG HTML specification, which explicitly requires that when sizes is present, all image candidates must use width descriptors. Second, browsers may ignore malformed srcset values or fall back to unexpected behavior, resulting in the wrong image being loaded — potentially hurting performance by downloading unnecessarily large files or degrading visual quality by selecting a too-small image. Third, standards-compliant markup ensures consistent, predictable behavior across all browsers and devices.
A common mistake is specifying a plain URL without any descriptor, or mixing density descriptors (1x, 2x) with the sizes attribute. An image candidate string without any descriptor defaults to 1x, which is a density descriptor — and that conflicts with the presence of sizes.
Examples
❌ Incorrect: Missing width descriptor with sizes present
<picture>
<source
srcset="image-small.jpg, image-large.jpg 1024w"
sizes="(max-width: 600px) 480px, 800px">
<img src="image-fallback.jpg" alt="A scenic landscape">
</picture>
Here, image-small.jpg has no width descriptor. Since sizes is present, this triggers the validation error.
❌ Incorrect: Using density descriptors with sizes
<img
srcset="image-1x.jpg 1x, image-2x.jpg 2x"
sizes="(max-width: 600px) 480px, 800px"
src="image-fallback.jpg"
alt="A scenic landscape">
Density descriptors (1x, 2x) are incompatible with the sizes attribute.
✅ Correct: All candidates have width descriptors
<picture>
<source
srcset="image-small.jpg 480w, image-large.jpg 1024w"
sizes="(max-width: 600px) 480px, 800px">
<img src="image-fallback.jpg" alt="A scenic landscape">
</picture>
Every image candidate now includes a width descriptor, which pairs correctly with the sizes attribute.
✅ Correct: Using density descriptors without sizes
If you want to use density descriptors instead of width descriptors, simply remove the sizes attribute:
<img
srcset="image-1x.jpg 1x, image-2x.jpg 2x"
src="image-fallback.jpg"
alt="A scenic landscape">
This is valid because density descriptors don't require (and shouldn't be used with) the sizes attribute.
✅ Correct: Width descriptors on <img> with sizes
<img
srcset="photo-320.jpg 320w, photo-640.jpg 640w, photo-1280.jpg 1280w"
sizes="(max-width: 400px) 320px, (max-width: 800px) 640px, 1280px"
src="photo-640.jpg"
alt="A close-up of a flower">
Each entry in srcset specifies its intrinsic width, and sizes tells the browser which display width to expect at each breakpoint. The browser then selects the best-fitting image automatically.
The tabindex attribute controls whether and in what order an element can receive keyboard focus. The W3C validator reports this error when it encounters tabindex="" because the HTML specification requires the attribute's value to be a valid integer — and an empty string cannot be parsed as one. This commonly happens when a value is accidentally omitted, when a template engine outputs a blank value, or when a CMS generates the attribute without a proper default.
Why this matters
Keyboard navigation is fundamental to web accessibility. Screen readers and assistive technologies rely on tabindex values to determine focus behavior. An empty tabindex attribute creates ambiguity: browsers may ignore it or handle it inconsistently, leading to unpredictable focus behavior for keyboard and assistive technology users. Beyond accessibility, it also means your HTML is invalid according to the WHATWG HTML living standard, which strictly defines tabindex as accepting only a valid integer.
How tabindex works
The attribute accepts an integer value with three meaningful ranges:
- Negative value (e.g.,
tabindex="-1"): The element can be focused programmatically (via JavaScript's.focus()), but it is excluded from the sequential keyboard tab order. tabindex="0": The element is added to the natural tab order based on its position in the document source. This is the most common way to make non-interactive elements (like a<div>or<span>) keyboard-focusable.- Positive value (e.g.,
tabindex="1",tabindex="5"): The element is placed in the tab order ahead of elements withtabindex="0"or notabindex, with lower numbers receiving focus first. Using positive values is generally discouraged because it overrides the natural document order and makes focus management harder to maintain.
How to fix it
- If the element should be focusable in tab order, set
tabindex="0". - If the element should only be focusable programmatically, set
tabindex="-1". - If you don't need custom focus behavior, remove the
tabindexattribute entirely. Interactive elements like<a>,<button>, and<input>are already focusable by default. - If a template or CMS generates the attribute, ensure the logic provides a valid integer or omits the attribute when no value is available.
Examples
❌ Empty tabindex value (triggers the error)
<div tabindex="">Click me</div>
<button tabindex="">Submit</button>
✅ Fixed: valid integer provided
<div tabindex="0">Click me</div>
<button tabindex="-1">Submit</button>
✅ Fixed: attribute removed when not needed
Interactive elements like <button> are focusable by default, so tabindex can simply be removed:
<button>Submit</button>
✅ Fixed: conditional rendering in a template
If you're using a templating system, ensure the attribute is only rendered when a valid value exists:
<!-- Instead of always outputting tabindex -->
<!-- Bad: <div tabindex="{{ tabindexValue }}"> -->
<!-- Only output the attribute when a value is set -->
<div tabindex="0">Interactive content</div>
A note on positive tabindex values
While positive integers like tabindex="1" or tabindex="3" are technically valid, they force a custom tab order that diverges from the visual and DOM order of the page. This creates confusion for keyboard users and is difficult to maintain as pages evolve. The WAI-ARIA Authoring Practices recommend avoiding positive tabindex values. Stick with 0 and -1 in nearly all cases.
The target attribute specifies where a linked document should be opened. When the validator encounters target="", it reports an error because the HTML specification requires browsing context names to be at least one character long. An empty string is not a valid browsing context name and has no defined behavior, which means browsers may handle it inconsistently.
This issue commonly arises when a target value is dynamically generated by a CMS, template engine, or JavaScript and the value ends up being empty. It can also happen when a developer adds the attribute with the intent to fill it in later but forgets to do so.
Setting target to an empty string is problematic for several reasons:
- Standards compliance: The WHATWG HTML specification explicitly requires valid browsing context names to be non-empty strings. An empty value violates this rule.
- Unpredictable behavior: Browsers may interpret an empty
targetdifferently — some may treat it like_self, others may behave unexpectedly. This makes your site harder to test and maintain. - Accessibility concerns: Screen readers and assistive technologies may announce the
targetattribute or use it to inform users about link behavior. An empty value provides no meaningful information.
To fix this, choose one of the following approaches:
- Remove the attribute if you want the default behavior (opening in the same browsing context, equivalent to
_self). - Set a valid keyword like
_blank,_self,_parent, or_top. - Set a custom name if you want multiple links to share the same browsing context (e.g.,
target="externalWindow").
Examples
❌ Invalid: empty target attribute
<a href="https://example.com" target="">Visit Example</a>
This triggers the validation error because the target value is an empty string.
✅ Fixed: remove target entirely
If you want the link to open in the current browsing context (the default), simply remove the attribute:
<a href="https://example.com">Visit Example</a>
✅ Fixed: use _blank to open in a new tab
<a href="https://example.com" target="_blank" rel="noopener">Visit Example</a>
Note the addition of rel="noopener" — this is a security best practice when using target="_blank", as it prevents the opened page from accessing the window.opener property.
✅ Fixed: use _self explicitly
If you want to be explicit about opening in the same context:
<a href="https://example.com" target="_self">Visit Example</a>
✅ Fixed: use a custom browsing context name
You can use a custom name so that multiple links reuse the same tab or window:
<a href="https://example.com" target="externalWindow">Example</a>
<a href="https://example.org" target="externalWindow">Example Org</a>
Both links will open in the same browsing context named externalWindow. If it doesn't exist yet, the browser creates it; subsequent clicks reuse it.
Dynamic templates
If your target value comes from a template or CMS, make sure the attribute is conditionally rendered rather than output with an empty value. For example, in a templating language:
<!-- Instead of always outputting target -->
<a href="https://example.com" target="">Visit</a>
<!-- Only include target when a value exists -->
<a href="https://example.com" target="_blank" rel="noopener">Visit</a>
In your template logic, conditionally omit the target attribute entirely when no value is provided, rather than rendering it as an empty string.
The target attribute on the <area> element tells the browser where to display the linked resource — in the current tab, a new tab, a parent frame, or a named <iframe>. According to the WHATWG HTML living standard, a valid navigable target must be either a keyword beginning with an underscore (_self, _blank, _parent, _top) or a name that is at least one character long. An empty string ("") satisfies neither condition, so the W3C validator reports:
Bad value "" for attribute "target" on element "area": Browsing context name must be at least one character long.
This commonly happens when templating engines or CMS platforms output target="" as a default, or when a value is conditionally set but the logic fails to produce a result.
Why this matters
- Standards compliance. An empty
targetviolates the HTML specification and produces a validation error. - Unpredictable browser behavior. While most browsers treat an empty
targetthe same as_self, this is not guaranteed by the spec. Relying on undefined behavior can lead to inconsistencies across browsers or future versions. - Code clarity. An empty
targetsignals unclear intent. Removing it or using an explicit keyword makes the code easier to understand and maintain.
How to fix it
- Remove the
targetattribute if you want the link to open in the same browsing context. This is the default behavior, equivalent totarget="_self". - Use a valid keyword like
_self,_blank,_parent, or_topif you need specific navigation behavior. - Use a named browsing context (e.g.,
target="contentFrame") if you want to direct the link to a specific<iframe>or window. The name must be at least one character long. - Fix your template logic if the empty value is being generated dynamically. Ensure the
targetattribute is only rendered when a non-empty value is available.
Examples
Invalid: empty target attribute
This triggers the validation error because target is set to an empty string:
<img src="floor-plan.png" usemap="#rooms" alt="Floor plan">
<map name="rooms">
<area shape="rect" coords="10,10,100,60" href="/kitchen" alt="Kitchen" target="">
</map>
Fixed: remove target for default behavior
If you want the link to open in the same tab (the default), simply remove the target attribute:
<img src="floor-plan.png" usemap="#rooms" alt="Floor plan">
<map name="rooms">
<area shape="rect" coords="10,10,100,60" href="/kitchen" alt="Kitchen">
</map>
Fixed: use a valid keyword
Use _self to be explicit about same-tab navigation, or _blank to open in a new tab:
<img src="floor-plan.png" usemap="#rooms" alt="Floor plan">
<map name="rooms">
<area shape="rect" coords="10,10,100,60" href="/kitchen" alt="Kitchen" target="_self">
<area shape="rect" coords="110,10,200,60" href="/bedroom" alt="Bedroom" target="_blank">
</map>
Fixed: target a named <iframe>
If you want to load the linked resource into a specific <iframe>, give the <iframe> a name attribute and reference it in target:
<iframe name="detailView" src="about:blank" title="Room details"></iframe>
<img src="floor-plan.png" usemap="#rooms" alt="Floor plan">
<map name="rooms">
<area shape="rect" coords="10,10,100,60" href="/kitchen" alt="Kitchen" target="detailView">
</map>
Fixed: conditionally render target in templates
If your target value comes from a variable, make sure the attribute is only output when the value is non-empty. For example, in a Jinja-style template:
<area shape="rect" coords="10,10,100,60" href="/kitchen" alt="Kitchen"
{% if target_value %} target="{{ target_value }}"{% endif %}>
This prevents target="" from appearing in your HTML when no value is set.
The type attribute on an anchor (<a>) element is an advisory hint that tells the browser what kind of content to expect at the link destination. According to the WHATWG HTML specification, when present, this attribute must contain a valid MIME type string. An empty string ("") is not a valid MIME type, so the W3C validator flags it as an error.
This issue commonly appears when a CMS, templating engine, or JavaScript framework generates the type attribute dynamically but produces an empty value when no MIME type is available. It can also happen when developers add the attribute as a placeholder intending to fill it in later.
Why this matters
While browsers generally handle an empty type attribute gracefully by ignoring it, there are good reasons to fix this:
- Standards compliance — An empty string violates the HTML specification's requirement for a valid MIME type, making your document invalid.
- Accessibility — Assistive technologies may use the
typeattribute to communicate the linked resource's format to users. An empty value provides no useful information and could lead to unexpected behavior in some screen readers. - Predictable behavior — Browsers are allowed to use the
typehint to influence how they handle a link (e.g., suggesting a download or choosing a handler). An empty value makes the intent ambiguous.
How to fix it
You have two straightforward options:
- Remove the
typeattribute — If you don't need to specify the MIME type, simply omit the attribute. This is the preferred approach when the type is unknown or unnecessary. - Provide a valid MIME type — If you want to hint at the linked resource's format, supply a proper MIME type string like
application/pdf,text/html,image/png,application/zip, etc.
The type attribute is purely advisory — the browser does not enforce it or refuse to follow the link if the actual content type differs. So omitting it is always safe.
Examples
Incorrect — empty type attribute
<a href="report.pdf" type="">Download Report</a>
This triggers the validation error because "" is not a valid MIME type.
Correct — attribute removed
<a href="report.pdf">Download Report</a>
Removing the type attribute entirely is the simplest fix and works perfectly when the MIME type hint isn't needed.
Correct — valid MIME type provided
<a href="report.pdf" type="application/pdf">Download Report</a>
If you want to explicitly indicate the format of the linked resource, use a proper MIME type value.
Multiple links with correct type usage
<ul>
<li><a href="slides.pptx" type="application/vnd.openxmlformats-officedocument.presentationml.presentation">Slides (PPTX)</a></li>
<li><a href="data.csv" type="text/csv">Data (CSV)</a></li>
<li><a href="https://example.com/about">About Us</a></li>
</ul>
In this example, the first two links include type attributes with valid MIME types to hint at the file format. The third link, pointing to a regular webpage, omits type entirely since it's not needed.
Fixing dynamically generated attributes
If your template engine produces empty type attributes, add a conditional check:
<!-- Instead of always outputting type="" -->
<!-- Only include the attribute when a value exists -->
<a href="report.pdf" type="application/pdf">Download Report</a>
In template logic, ensure you only render the type attribute when a non-empty MIME type value is available. Otherwise, omit the attribute from the output altogether.
The HTML specification defines that the width and height attributes on <iframe> elements must contain a valid non-negative integer — that is, a string of one or more digits representing a number zero or greater (e.g., "0", "300", "600"). When one of these attributes is set to an empty string (width="" or height=""), the validator raises this error because an empty string cannot be parsed as a valid integer.
This commonly happens when a CMS, template engine, or JavaScript framework outputs an <iframe> with a dynamic dimension value that ends up being blank. It can also occur when developers remove the value but leave the attribute in place, or when copy-pasting embed code and accidentally clearing the value.
While most browsers will fall back to their default iframe dimensions (typically 300×150 pixels) when they encounter an empty value, relying on this behavior is not standards-compliant. Invalid attribute values can cause unpredictable rendering across different browsers, interfere with layout calculations, and make your markup harder to maintain. Assistive technologies may also have trouble determining the intended dimensions of the iframe.
How to fix it
You have a few options:
- Set a valid integer value. If you know the desired dimensions, specify them directly as non-negative integers. The values represent pixels.
- Remove the attribute entirely. If you don't need to set dimensions via HTML attributes, remove the empty
widthorheightattribute. The browser will apply its default size, or you can control sizing with CSS. - Use CSS instead. For responsive designs or more flexible sizing, remove the HTML attributes and use CSS properties like
width,height,max-width, oraspect-ratio.
Note that these attributes accept only plain integers — no units, no percentages, and no decimal points. For example, width="600" is valid, but width="600px" or width="100%" is not.
Examples
❌ Invalid: empty string values
<iframe src="https://example.com" width="" height=""></iframe>
Both width and height are set to empty strings, which are not valid non-negative integers.
✅ Fixed: specify valid integer values
<iframe src="https://example.com" width="600" height="400"></iframe>
✅ Fixed: remove the empty attributes
<iframe src="https://example.com"></iframe>
The browser will use its default dimensions (typically 300×150 pixels).
✅ Fixed: remove attributes and use CSS for sizing
<iframe src="https://example.com" style="width: 100%; height: 400px;"></iframe>
This approach is especially useful for responsive layouts where a fixed pixel width in HTML doesn't make sense.
✅ Fixed: responsive iframe with CSS aspect ratio
<iframe
src="https://example.com/video"
style="width: 100%; aspect-ratio: 16 / 9; border: none;">
</iframe>
Using aspect-ratio in CSS lets the iframe scale responsively while maintaining its proportions, without needing width or height attributes at all.
The HTML specification requires that the width and height attributes on <img> elements, when present, contain a string representing a non-negative integer — that is, a sequence of one or more ASCII digits like "0", "150", or "1920". An empty string ("") does not satisfy this requirement, so the W3C validator flags it as an error.
This issue commonly arises when:
- A CMS or templating engine outputs
width=""orheight=""because no dimension value was configured. - JavaScript dynamically sets
img.setAttribute("width", "")instead of removing the attribute. - A developer adds the attributes as placeholders intending to fill them in later but forgets to do so.
Why it matters
Providing valid width and height attributes is one of the most effective ways to prevent Cumulative Layout Shift (CLS). Browsers use these values to calculate the image's aspect ratio and reserve the correct amount of space before the image loads. When the values are empty strings, the browser cannot determine the aspect ratio, so no space is reserved — leading to layout shifts as images load in, which hurts both user experience and Core Web Vitals scores.
Beyond performance, invalid attribute values can cause unpredictable rendering behavior across browsers. Some browsers may ignore the attribute, others may interpret the empty string as 0, collapsing the image to zero pixels in that dimension. Standards-compliant HTML also improves accessibility by ensuring assistive technologies can parse the document reliably.
Examples
❌ Invalid: empty string values
<img src="photo.jpg" alt="A sunset over the ocean" width="" height="">
Both width and height are set to empty strings, which is not valid.
✅ Fixed: provide actual dimensions
<img src="photo.jpg" alt="A sunset over the ocean" width="800" height="600">
Replace the empty strings with the image's actual pixel dimensions. These values should reflect the image's intrinsic (natural) size. CSS can still be used to scale the image visually — the browser will use the width and height ratio to reserve the correct space.
✅ Fixed: remove the attributes entirely
<img src="photo.jpg" alt="A sunset over the ocean">
If you don't know the dimensions or prefer to handle sizing purely through CSS, remove the attributes altogether. An absent attribute is valid; an empty one is not.
❌ Invalid: only one attribute is empty
<img src="banner.jpg" alt="Promotional banner" width="1200" height="">
Even if only one attribute has an empty value, the validation error will be triggered for that attribute.
✅ Fixed: both attributes with valid values
<img src="banner.jpg" alt="Promotional banner" width="1200" height="400">
Fixing dynamic/template-generated markup
If a template language is outputting empty attributes, use a conditional to omit them when no value is available. For example, in a template:
<!-- Instead of always outputting the attributes: -->
<img src="photo.jpg" alt="Description" width="" height="">
<!-- Conditionally include them only when values exist: -->
<img src="photo.jpg" alt="Description" width="800" height="600">
If you're setting dimensions via JavaScript, remove the attribute rather than setting it to an empty string:
// ❌ Don't do this
img.setAttribute("width", "");
// ✅ Do this instead
img.removeAttribute("width");
// ✅ Or set a valid value
img.setAttribute("width", "800");
A note on values
The width and height attributes only accept non-negative integers — whole numbers without units, decimals, or percentage signs. Values like "100px", "50%", or "3.5" are also invalid. Use plain integers like "100" or "600". If you need responsive sizing with percentages or other CSS units, apply those through CSS styles instead.
The xmlns attribute declares the XML namespace for an element. For SVG elements, the only permitted namespace is "http://www.w3.org/2000/svg". When this attribute is present but set to an empty string ("") or any value other than the correct namespace, the W3C validator reports an error because the browser cannot properly associate the element with the SVG specification.
In HTML5 documents (served as text/html), the xmlns attribute on <svg> is actually optional. The HTML parser automatically associates <svg> elements with the correct SVG namespace without needing an explicit declaration. However, if you do include the xmlns attribute — for example, because your SVG was exported from a design tool or copied from an XML-based source — it must contain the exact value "http://www.w3.org/2000/svg". An empty or incorrect value will cause a validation error and could lead to rendering issues in certain contexts.
This matters for several reasons:
- Standards compliance: The HTML specification explicitly restricts the allowed value for
xmlnson SVG elements. - Browser compatibility: While most modern browsers are forgiving in HTML mode, an incorrect namespace can cause problems when SVG content is used in XML contexts (such as XHTML or standalone
.svgfiles). - Interoperability: Tools and libraries that process your HTML may rely on the correct namespace to identify and manipulate SVG elements.
To fix this issue, you have two options:
- Set the correct value: Replace the empty or incorrect
xmlnsvalue with"http://www.w3.org/2000/svg". - Remove the attribute entirely: Since
xmlnsis optional in HTML5, simply removing it is often the cleanest solution.
Examples
Incorrect: empty xmlns attribute
This triggers the validation error because the namespace value is an empty string:
<svg xmlns="" width="100" height="100">
<circle cx="50" cy="50" r="40" fill="red" />
</svg>
Incorrect: wrong namespace value
Any value other than the correct SVG namespace will also trigger this error:
<svg xmlns="http://www.w3.org/2000/html" width="100" height="100">
<circle cx="50" cy="50" r="40" fill="red" />
</svg>
Fix: use the correct namespace
Set xmlns to the only permitted value:
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
<circle cx="50" cy="50" r="40" fill="red" />
</svg>
Fix: remove the xmlns attribute
In an HTML5 document, you can omit xmlns altogether since the parser handles the namespace automatically:
<svg width="100" height="100">
<circle cx="50" cy="50" r="40" fill="red" />
</svg>
Note on inline SVG from external sources
Design tools like Figma, Illustrator, or Inkscape often export SVG files with the xmlns attribute already set correctly. If you're copying SVG markup and the xmlns value gets accidentally cleared or corrupted during the process, either restore it to "http://www.w3.org/2000/svg" or remove it before embedding the SVG in your HTML. Both approaches will produce valid, working markup.
The role="group" attribute is not allowed on the article element because article already has an implicit ARIA role of article, and group is not among the roles permitted on this element.
The article element represents a self-contained composition in a document, such as a blog post, a news story, or a forum comment. Its implicit ARIA role is article. According to the ARIA in HTML specification, the article element can only use a limited set of roles: application, document, feed, main, none, presentation, or region. The group role is not in that list.
If you need a group role, use a generic element like div or span instead. If you need the semantic meaning of article, keep the article element and remove the role="group" attribute.
Example with the issue
<article role="group">
<h2>Latest news</h2>
<p>Content of the article.</p>
</article>
How to fix it
If group semantics are what you need, switch to a div:
<div role="group" aria-label="Latest news">
<h2>Latest news</h2>
<p>Content of the article.</p>
</div>
If article semantics are what you need, drop the conflicting role:
<article>
<h2>Latest news</h2>
<p>Content of the article.</p>
</article>
The W3C HTML specification restricts which ARIA roles can be used on specific elements. An li element already carries the implicit role of listitem when it's a child of a ul or ol, so adding an explicit role is often unnecessary. The group role, as defined in the WAI-ARIA specification, is meant for container elements that form a logical collection of related items — similar to how a fieldset groups form controls. Applying group to an li element contradicts the element's purpose as an individual item within a list.
This matters for several reasons. Assistive technologies like screen readers rely on ARIA roles to communicate the structure and purpose of content to users. When an li element is marked with role="group", it overrides the native listitem semantics, potentially confusing users who depend on these tools. A screen reader might announce the element as a group container rather than a list item, breaking the expected navigation pattern of the list. Browsers and assistive technologies are optimized around correct role usage, so invalid combinations can lead to unpredictable behavior.
When you might actually need group
If your intent is to group a set of related elements together, the group role belongs on a wrapping container — not on the individual items inside it. For example, you might use role="group" on a div or a ul that contains a subset of related controls within a larger interface. If an li contains nested interactive content that needs to be grouped, wrap that content in an inner container with the group role instead.
How to fix it
- Remove the role entirely if the
liis a standard list item inside aulorol. The browser already provides the correctlistitemsemantics. - Move the
grouprole to a container element if you genuinely need to create a labeled group of related items. - Use a different valid role if the
liserves a non-standard purpose, such asmenuitem,option,tab,treeitem, orpresentation, depending on the widget pattern you're building.
Examples
Incorrect: group role on li elements
<ul>
<li role="group">Fruits</li>
<li role="group">Vegetables</li>
<li role="group">Grains</li>
</ul>
This triggers the validation error because group is not a permitted role for li.
Correct: no explicit role needed
<ul>
<li>Fruits</li>
<li>Vegetables</li>
<li>Grains</li>
</ul>
Each li inside a ul automatically has the listitem role. No additional markup is needed.
Correct: using group on a container element
If you need to group related items with a label, apply the group role to the container:
<div role="group" aria-labelledby="food-heading">
<h2 id="food-heading">Food Categories</h2>
<ul>
<li>Fruits</li>
<li>Vegetables</li>
<li>Grains</li>
</ul>
</div>
Correct: nested groups within list items
If each list item contains a group of related controls, place the group role on an inner wrapper:
<ul>
<li>
<div role="group" aria-label="Text formatting">
<button>Bold</button>
<button>Italic</button>
<button>Underline</button>
</div>
</li>
<li>
<div role="group" aria-label="Text alignment">
<button>Left</button>
<button>Center</button>
<button>Right</button>
</div>
</li>
</ul>
This preserves the list structure while correctly applying the group role to containers of related widgets. The aria-label attribute gives each group an accessible name, which is recommended when using role="group".
A space before the width attribute value is causing the validator to misparse the iframe attributes, likely due to a missing closing quote on the width attribute.
This error typically occurs when there's a typo in the attribute syntax, such as a missing closing quote or extra spaces inside the attribute value. The validator reads the raw HTML and interprets " height= as part of the width value because the width attribute's opening quote was never properly closed.
The width and height attributes on an iframe element accept non-negative integer values representing pixels. Each attribute must have its value properly quoted and contain only digits.
HTML Examples
❌ Incorrect
<iframe src="page.html" width="600 height="400"></iframe>
In this example, the closing quote after 600 is missing. The validator sees the width value as 600 height=, which is not a valid number.
✅ Correct
<iframe src="page.html" width="600" height="400"></iframe>
Each attribute has properly matched opening and closing quotes, and the values contain only digits.
The fetchpriority attribute is a hint to the browser about the relative priority of fetching a particular resource compared to other resources of the same type. It is defined in the WHATWG HTML living standard as an enumerated attribute with exactly three valid values:
high— The resource should be fetched at a higher priority relative to other resources of the same type.low— The resource should be fetched at a lower priority relative to other resources of the same type.auto— The browser determines the appropriate priority (this is the default behavior).
Values like "highest", "critical", "urgent", or any other string outside these three are not recognized. When the W3C validator encounters an invalid value, it reports: Bad value "highest" for attribute "fetchpriority" on element "link".
Why This Matters
Standards compliance: Browsers treat unrecognized fetchpriority values as equivalent to "auto", meaning your intended priority hint is silently ignored. If you wrote fetchpriority="highest" expecting it to be even more urgent than "high", that extra emphasis has no effect — the browser simply falls back to its default prioritization.
Developer intent: An invalid value masks your real intention. Another developer reading the code might assume "highest" does something special, when in reality the browser discards it. Using the correct value makes the code's purpose clear and ensures the hint is actually applied.
Accessibility and performance: The fetchpriority attribute is commonly used on <link rel="preload"> elements for critical resources like fonts, stylesheets, or hero images. If your priority hint is silently ignored due to an invalid value, key resources may not load as quickly as intended, potentially degrading the user experience.
How to Fix It
Replace the invalid value with one of the three accepted values. In most cases, if you used "highest", you likely meant "high":
- Find every
<link>element wherefetchpriorityhas an invalid value. - Change the value to
"high","low", or"auto". - If you're unsure which priority to use, omit the attribute entirely — the browser will use
"auto"by default.
Note that fetchpriority also works on <img>, <script>, and <iframe> elements, and the same three-value restriction applies to all of them.
Examples
Incorrect: Invalid fetchpriority value
<link rel="preload" href="hero.webp" as="image" fetchpriority="highest">
The value "highest" is not valid. The browser ignores the hint and falls back to default prioritization.
Correct: Using "high" for elevated priority
<link rel="preload" href="hero.webp" as="image" fetchpriority="high">
Correct: Using "low" for deferred resources
<link rel="preload" href="analytics.js" as="script" fetchpriority="low">
Correct: Omitting the attribute for default behavior
<link rel="preload" href="style.css" as="style">
When omitted, the browser uses its default priority logic, which is equivalent to fetchpriority="auto".
Full document example
<!DOCTYPE html>
<html lang="en">
<head>
<title>Fetch Priority Example</title>
<link rel="preload" href="hero.webp" as="image" fetchpriority="high">
<link rel="preload" href="fonts/body.woff2" as="font" type="font/woff2" crossorigin fetchpriority="high">
<link rel="stylesheet" href="style.css">
</head>
<body>
<img src="hero.webp" alt="Hero banner" fetchpriority="high">
<p>Page content goes here.</p>
</body>
</html>
This example preloads a hero image and a font with fetchpriority="high", and also applies the hint to the <img> element itself — all using valid attribute values.
When you set href="http://", the browser and the W3C validator attempt to parse this as an absolute URL. According to the URL Standard, a URL with the http or https scheme must include a non-empty host component. The string http:// has the scheme but nothing after the ://, which makes the host empty and the URL invalid.
This issue typically arises when a URL is dynamically generated but the variable or value for the domain is missing, or when a developer uses http:// as a temporary placeholder during development and forgets to replace it.
Why this matters
- Broken navigation: Clicking a link with
href="http://"leads to unpredictable behavior. Some browsers may navigate to an error page, while others may interpret it differently. - Accessibility: Screen readers announce links to users, including their destinations. An invalid URL creates a confusing experience for assistive technology users who expect the link to go somewhere meaningful.
- Standards compliance: The HTML specification requires that
hrefvalues be valid URLs. An empty host violates the URL parsing rules, causing the W3C validator to flag it as an error. - SEO: Search engine crawlers may treat invalid URLs as errors, potentially affecting how your site is indexed.
Examples
❌ Invalid: empty host in URL
<a href="http://">Visit our website</a>
This triggers the error because http:// has no host component.
❌ Invalid: same issue with HTTPS
<a href="https://">Secure link</a>
The https scheme also requires a valid host, so this produces the same error.
✅ Fixed: provide a complete URL
<a href="https://example.com">Visit our website</a>
✅ Fixed: use a fragment placeholder if the URL is unknown
If you need a placeholder link during development, use # instead of an incomplete URL:
<a href="#">Visit our website</a>
✅ Fixed: use a relative URL when linking within the same site
<a href="/about">About us</a>
Handling dynamic URLs
If the href value comes from a template or CMS, make sure the variable outputs a complete URL. For example, if a template produces an empty string, you might end up with:
<!-- If {{ site_url }} is empty, this becomes href="http://" -->
<a href="http://{{ site_url }}">Home</a>
Ensure that the variable always resolves to a valid host, or add a fallback so the link is omitted or replaced with a safe default when the value is missing.
The xmlns attribute declares the XML namespace for the document. When present on the <html> element, the HTML specification requires its value to be exactly http://www.w3.org/1999/xhtml — no variations allowed. The URL http://www.w3.org/1999/html is not a recognized namespace and will be rejected by the validator. This error almost always comes from a typo: the "x" before "html" was accidentally omitted.
Why this matters
While most browsers will still render the page in HTML mode regardless of a malformed xmlns value, an incorrect namespace can cause real problems in certain contexts:
- XHTML processing: If the document is served with an XML content type (e.g.,
application/xhtml+xml), an invalid namespace will cause XML parsers to reject or misinterpret the document. - Standards compliance: Validators and automated tools flag this as an error, which can affect quality audits, accessibility checks, and CI/CD pipelines that enforce valid markup.
- Tooling and interoperability: XML-based tools, content management systems, and XSLT transformations rely on correct namespaces to function properly.
How to fix it
You have two options depending on your document type:
- If you need the
xmlnsattribute (e.g., for XHTML or polyglot documents): Change the value fromhttp://www.w3.org/1999/htmltohttp://www.w3.org/1999/xhtml. - If you're writing standard HTML5: Simply remove the
xmlnsattribute. It's optional in HTML5 and has no effect when present with the correct value — so omitting it is the cleanest approach.
Examples
Incorrect — misspelled namespace
The value is missing the "x" before "html":
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/html" lang="en">
<head>
<title>My Page</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
Fixed — correct XHTML namespace
Add the missing "x" so the value reads xhtml:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
<title>My Page</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
Fixed — standard HTML5 without xmlns
If you don't need XHTML compatibility, remove the attribute altogether:
<!DOCTYPE html>
<html lang="en">
<head>
<title>My Page</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
For most modern websites served as text/html, the third option — omitting xmlns entirely — is the simplest and recommended approach. Only include it if your document must also be valid XHTML or will be processed by XML tooling, and always ensure the value is exactly http://www.w3.org/1999/xhtml.
The xmlns attribute declares the XML namespace for a document. The value http://www.w3.org/TR/REC-html40 is a URL that points to the old HTML 4.0 Recommendation specification — it was never a proper XML namespace identifier. It likely ended up in code through confusion between DTD/specification URLs and actual namespace URIs, or by copying markup from outdated templates.
In the HTML5 specification (the WHATWG HTML Living Standard), the xmlns attribute on the <html> element is optional. When present, its value must be exactly http://www.w3.org/1999/xhtml — no other value is permitted. This is true regardless of whether the document is served as text/html or application/xhtml+xml.
Why this matters
- Validation failure: The W3C validator will reject the document because the namespace value is not one of the allowed values.
- Standards compliance: Using an incorrect namespace can cause XML parsers to misinterpret or reject the document, especially when served with an XML content type.
- Legacy confusion: The
http://www.w3.org/TR/REC-html40URL is a specification reference, not a namespace. Namespaces and specification URLs serve fundamentally different purposes in web standards.
How to fix it
The simplest fix for a standard HTML5 document is to remove the xmlns attribute entirely. The HTML parser does not require it, and browsers will process the document correctly without it.
If your document is served as XHTML (application/xhtml+xml), or if you have a specific reason to include the namespace declaration, update the value to the only permitted one: http://www.w3.org/1999/xhtml.
Examples
❌ Incorrect: old HTML 4.0 URL used as namespace
<!DOCTYPE html>
<html xmlns="http://www.w3.org/TR/REC-html40" lang="en">
<head>
<title>My Page</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
✅ Fix option 1: remove the xmlns attribute (recommended for HTML5)
For most HTML5 documents served as text/html, simply omit the attribute:
<!DOCTYPE html>
<html lang="en">
<head>
<title>My Page</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
✅ Fix option 2: use the correct namespace value
If you need the xmlns attribute (e.g., for XHTML serialization), set it to the only allowed value:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
<title>My Page</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
Other incorrect values to watch for
This same error can appear with other invalid namespace URLs. All of the following are wrong:
http://www.w3.org/TR/REC-html40(HTML 4.0 spec URL)http://www.w3.org/TR/html4/(another HTML 4 spec URL)http://www.w3.org/1999/html(non-existent namespace)
The only valid value is http://www.w3.org/1999/xhtml. When in doubt, remove the xmlns attribute altogether — modern HTML5 documents don't need it.
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