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.
Backslashes are not valid delimiters in URLs according to the URL Living Standard. While some browsers may silently normalize backslashes to forward slashes, this behavior is non-standard and should not be relied upon. Using backslashes in URLs can lead to broken images, unexpected behavior across different browsers, and failures in environments that strictly follow URL specifications (such as HTTP servers, CDNs, or validation tools).
This issue commonly arises when developers copy file paths directly from a Windows file system — where \ is the directory separator — and paste them into HTML src attributes. It can also happen when server-side code generates URLs using OS-level path functions instead of URL-building utilities.
Beyond standards compliance, this matters for several practical reasons:
- Cross-browser reliability: Not all browsers or HTTP clients normalize backslashes the same way.
- Server compatibility: Many web servers interpret backslashes literally, resulting in 404 errors.
- Portability: Code with backslash paths may work in local development on Windows but break when deployed to a Linux-based server.
To fix the issue, locate every backslash in the src attribute value and replace it with a forward slash. This applies to all URL contexts, not just img elements — though the validator specifically flags it here.
Examples
❌ Incorrect: backslashes in the src path
<imgsrc="images\photos\landscape.jpg"alt="Mountain landscape">
<imgsrc="https://example.com\img\small\photo.png"alt="Example image">
Both of these use backslashes as path delimiters, which triggers the validation error.
✅ Correct: forward slashes in the src path
<imgsrc="images/photos/landscape.jpg"alt="Mountain landscape">
<imgsrc="https://example.com/img/small/photo.png"alt="Example image">
Simply replacing \ with / resolves the issue and produces a valid, portable URL.
❌ Incorrect: mixed delimiters
<imgsrc="assets/images\banner\hero.webp"alt="Hero banner">
Even a single backslash in an otherwise valid path will trigger this error.
✅ Correct: consistent forward slashes
<imgsrc="assets/images/banner/hero.webp"alt="Hero banner">
Tips to avoid this issue
- Don't copy-paste Windows file paths directly into HTML. Always convert backslashes to forward slashes.
- Use your editor's find-and-replace to search for
\withinsrcattributes across your project. - If generating URLs in server-side code, use URL-building functions rather than file-system path functions. For example, in Node.js, use the
urlmodule or template literals with/instead ofpath.join(), which uses\on Windows. - Run the W3C validator regularly during development to catch issues like this before deployment.
URLs follow strict syntax rules defined by RFC 3986. Within a URL's path segment, only a specific set of characters is allowed to appear literally. When a character falls outside this allowed set, it must be percent-encoded — represented as a % sign followed by two hexadecimal digits corresponding to the character's ASCII code. The W3C validator checks that every URL in your HTML conforms to these rules, and it flags any src value that contains raw illegal characters.
Characters that commonly trigger this error include:
| Character | Percent-encoded |
|---|---|
| (space) | %20 |
[ | %5B |
] | %5D |
{ | %7B |
} | %7D |
| | %7C |
^ | %5E |
` | %60 |
Other reserved characters like ?, #, @, !, $, &, ', (, ), *, +, ,, ;, and = also need encoding when used as literal data in a path segment rather than as URL delimiters. The % character itself must be encoded as %25 if it appears literally.
Why This Is a Problem
- Browser inconsistency: While many modern browsers silently fix malformed URLs, not all do. Some browsers, older user agents, or HTTP clients may fail to load the resource or interpret the URL differently, leading to broken images.
- Standards compliance: Invalid URLs violate the HTML specification, which requires that attribute values containing URLs conform to valid URL syntax.
- Interoperability: Servers, CDNs, proxies, and caching layers may handle illegal characters unpredictably, causing intermittent failures that are difficult to debug.
- Accessibility: If a URL is malformed and the image fails to load, users relying on assistive technologies may not receive the intended content, even when appropriate
alttext is provided.
How to Fix It
You have two main approaches:
- Percent-encode the illegal characters in the
srcvalue. Replace each offending character with its%XXequivalent. - Rename the file to use only URL-safe characters. Stick to lowercase letters, digits, hyphens (
-), underscores (_), and dots (.). This is the cleanest long-term solution.
If you're generating URLs programmatically, use your language's built-in URL encoding functions (e.g., encodeURIComponent() in JavaScript, urlencode() in PHP, or urllib.parse.quote() in Python).
Examples
Illegal characters in the filename
The square brackets in the src value are not allowed in a URL path segment:
<!-- ❌ Invalid: raw [ and ] in URL path -->
<imgsrc="image[00].svg"alt="Company logo">
Fix by percent-encoding:
<!-- ✅ Valid: [ and ] are percent-encoded -->
<imgsrc="image%5B00%5D.svg"alt="Company logo">
Fix by renaming the file:
<!-- ✅ Valid: filename uses only safe characters -->
<imgsrc="image-00.svg"alt="Company logo">
Spaces in the filename
Spaces are one of the most common causes of this error:
<!-- ❌ Invalid: space in URL path -->
<imgsrc="my photo.jpg"alt="Vacation photo">
<!-- ✅ Valid: space encoded as %20 -->
<imgsrc="my%20photo.jpg"alt="Vacation photo">
<!-- ✅ Valid: filename uses a hyphen instead of a space -->
<imgsrc="my-photo.jpg"alt="Vacation photo">
Curly braces in a template-like path
Sometimes filenames or paths contain curly braces from templating artifacts or naming conventions:
<!-- ❌ Invalid: raw { and } in URL path -->
<imgsrc="icons/{home}.png"alt="Home icon">
<!-- ✅ Valid: curly braces percent-encoded -->
<imgsrc="icons/%7Bhome%7D.png"alt="Home icon">
Best practice for file naming
The simplest way to avoid this error entirely is to adopt a consistent file naming convention that only uses URL-safe characters:
<!-- ✅ Valid: clean, URL-safe filenames -->
<imgsrc="images/hero-banner-2024.webp"alt="Welcome banner">
<imgsrc="photos/team_photo_01.jpg"alt="Our team">
URLs follow strict syntax rules defined by RFC 3986, which does not allow literal space characters in any part of a URL — whether in the path, query string, or fragment. While many browsers will silently handle spaces by encoding them before making a request, the raw HTML is still invalid. The W3C HTML validator flags this because the src attribute expects a valid URL, and a URL containing a raw space does not conform to the standard.
This issue commonly appears in two scenarios: spaces in file paths (e.g., my image.jpg) and spaces in query string values (e.g., ?search=my term). Both must be percent-encoded. The percent-encoded form of a space is %20. In query strings specifically, you may also see + used to represent spaces (as defined by application/x-www-form-urlencoded), which is also valid in that context.
Beyond standards compliance, raw spaces in URLs can cause real problems. Some older browsers or HTTP clients may truncate the URL at the first space, leading to broken images or failed resource loads. Spaces can also cause issues with link sharing, copy-pasting, and server-side URL parsing. Proper encoding ensures your URLs work reliably across all environments.
How to fix it
- Replace spaces with
%20in all parts of the URL. This is the universally safe approach. - Rename files to avoid spaces altogether. Use hyphens (
-) or underscores (_) instead of spaces in file and directory names. - Use
+in query strings if you prefer, though%20works everywhere in a URL.
If you're generating URLs programmatically, use built-in encoding functions like JavaScript's encodeURI() or encodeURIComponent() to handle this automatically.
Examples
Spaces in the file path
This triggers the validation error because the file name contains a space:
<!-- ❌ Invalid: space in path segment -->
<imgsrc="/images/my photo.jpg"alt="A vacation photo">
Fix it by encoding the space:
<!-- ✅ Valid: space encoded as %20 -->
<imgsrc="/images/my%20photo.jpg"alt="A vacation photo">
Or better yet, rename the file to avoid spaces:
<!-- ✅ Valid: no spaces in file name -->
<imgsrc="/images/my-photo.jpg"alt="A vacation photo">
Spaces in the query string
This triggers the error because the query parameter value contains a space:
<!-- ❌ Invalid: space in query string -->
<imgsrc="https://example.com/image?title=sunset beach"alt="Sunset at the beach">
Fix by percent-encoding the space:
<!-- ✅ Valid: space encoded as %20 -->
<imgsrc="https://example.com/image?title=sunset%20beach"alt="Sunset at the beach">
Using + is also acceptable in query strings:
<!-- ✅ Valid: space encoded as + in query string -->
<imgsrc="https://example.com/image?title=sunset+beach"alt="Sunset at the beach">
Multiple spaces in a URL
When a URL has multiple spaces, each one must be encoded:
<!-- ❌ Invalid: multiple spaces -->
<imgsrc="/uploads/user photos/trip to paris.jpg"alt="Trip to Paris">
<!-- ✅ Valid: all spaces encoded -->
<imgsrc="/uploads/user%20photos/trip%20to%20paris.jpg"alt="Trip to Paris">
URLs follow a strict syntax defined by the URL Living Standard and RFC 3986. Only a specific set of characters are allowed to appear literally in a URL's query string. Characters outside this set — such as pipes, square brackets, curly braces, and certain other symbols — must be percent-encoded. Percent-encoding replaces the character with a % sign followed by its two-digit hexadecimal ASCII code.
When the W3C HTML Validator encounters an <img> tag whose src attribute contains an illegal character in the query portion of the URL, it raises this error. The query string is the part of the URL that comes after the ? character.
Why this matters
- Browser inconsistency: While many modern browsers will silently fix malformed URLs, not all browsers or HTTP clients handle illegal characters the same way. Some may misinterpret the URL or fail to load the resource entirely.
- Standards compliance: Valid URLs are a foundational requirement for interoperable web content. Using illegal characters violates both the HTML and URL specifications.
- Interoperability: Automated tools, web crawlers, proxies, and content delivery networks may reject or mangle URLs containing unencoded special characters, leading to broken images.
- Accessibility: Screen readers and assistive technologies rely on valid markup. Malformed URLs can cause unexpected behavior in these tools.
Common illegal characters and their encodings
Here are characters frequently flagged by the validator:
| Character | Percent-encoded |
|---|---|
| (pipe) | %7C |
[ | %5B |
] | %5D |
{ | %7B |
} | %7D |
^ | %5E |
` (backtick) | %60 |
| (space) | %20 |
How to fix it
Identify the illegal characters in the src URL and replace each one with its corresponding percent-encoded value. If you're generating URLs dynamically with a programming language, use the language's built-in URL-encoding function (e.g., encodeURI() or encodeURIComponent() in JavaScript, urlencode() in PHP, urllib.parse.quote() in Python).
Examples
❌ Incorrect: unencoded pipe character in query string
<imgsrc="https://example.com/image?filter=red|blue"alt="Filtered image">
The | character is not allowed literally in the query string.
✅ Correct: pipe character percent-encoded
<imgsrc="https://example.com/image?filter=red%7Cblue"alt="Filtered image">
❌ Incorrect: unencoded square brackets in query string
<imgsrc="https://example.com/image?size[width]=300&size[height]=200"alt="Resized image">
The [ and ] characters must be encoded.
✅ Correct: square brackets percent-encoded
<imgsrc="https://example.com/image?size%5Bwidth%5D=300&size%5Bheight%5D=200"alt="Resized image">
❌ Incorrect: space in query string
<imgsrc="https://example.com/image?caption=hello world"alt="Captioned image">
✅ Correct: space percent-encoded
<imgsrc="https://example.com/image?caption=hello%20world"alt="Captioned image">
Encoding URLs dynamically
If your URLs are built in JavaScript, use encodeURIComponent() for individual query parameter values:
constfilter="red|blue";
consturl=`https://example.com/image?filter=${encodeURIComponent(filter)}`;
// Result: "https://example.com/image?filter=red%7Cblue"
This ensures that any special characters in user-provided or dynamic values are properly encoded before being placed into the HTML.
URLs follow strict syntax rules defined by RFC 3986, which does not allow literal space characters. When the W3C validator encounters a space in the src attribute of an <img> element, it reports it as an illegal character in the scheme data. While most modern browsers will attempt to handle spaces in URLs by automatically encoding them, relying on this behavior is not standards-compliant and can lead to broken images in certain contexts, such as when URLs are processed by other tools, APIs, or older browsers.
This issue commonly arises when file names contain spaces (e.g., my photo.jpg) and the path is copied directly into the HTML. It can also happen when a URL is incorrectly constructed by concatenating strings with unencoded values.
Beyond validation, unencoded spaces can cause real problems. A URL with a space may break when shared, copied, or passed through redirects. Email clients and messaging apps may truncate the URL at the space. Search engine crawlers might fail to index the resource correctly.
How to fix it
There are several ways to resolve this issue:
- Percent-encode spaces as
%20— Replace every literal space in the URL with%20. - Rename the file — Remove spaces from file names entirely, using hyphens (
-), underscores (_), or camelCase instead. - Use proper URL encoding functions — If generating URLs dynamically (e.g., in JavaScript or a server-side language), use built-in encoding functions like
encodeURI()orencodeURIComponent().
Renaming files to avoid spaces is generally the best long-term practice, as it prevents encoding issues across your entire workflow.
Examples
❌ Invalid: spaces in the src attribute
<imgsrc="images/my photo.jpg"alt="A vacation photo">
<imgsrc="/assets/blog posts/header image.png"alt="Blog header">
Both of these will trigger the validation error because the src value contains literal space characters.
✅ Fixed: spaces encoded as %20
<imgsrc="images/my%20photo.jpg"alt="A vacation photo">
<imgsrc="/assets/blog%20posts/header%20image.png"alt="Blog header">
✅ Fixed: file renamed to remove spaces
<imgsrc="images/my-photo.jpg"alt="A vacation photo">
<imgsrc="/assets/blog-posts/header-image.png"alt="Blog header">
A note on + vs %20
You may see spaces encoded as + in some contexts (e.g., query strings in form submissions using application/x-www-form-urlencoded). However, + is not a valid substitute for a space in a URL path. Always use %20 for spaces in the src attribute.
<!-- ❌ Incorrect: + does not represent a space in a URL path -->
<imgsrc="images/my+photo.jpg"alt="A vacation photo">
<!-- ✅ Correct -->
<imgsrc="images/my%20photo.jpg"alt="A vacation photo">
In URLs, special characters that aren't part of the standard allowed set must be represented using percent-encoding (also called URL encoding). This works by replacing the character with a % followed by two hexadecimal digits representing its byte value — for example, a space becomes %20, and an ampersand becomes %26. Because % itself serves as the escape character in this scheme, any bare % that isn't followed by two hexadecimal digits creates an ambiguous, invalid URL.
When the W3C validator encounters a src attribute containing a % not followed by two valid hex digits, it cannot determine the intended character and reports the error. This issue typically arises in two scenarios:
- A literal percent sign in the URL — for instance, a query parameter like
?width=48%where the%is meant as an actual percent symbol. The%must be encoded as%25. - Incomplete or corrupted percent-encoding — such as
%2instead of%20, or%GZwhere the characters after%aren't valid hexadecimal digits (only0–9andA–F/a–fare valid).
Why this matters
- Browser inconsistency: While many browsers try to handle malformed URLs gracefully, behavior varies. Some browsers may misinterpret the intended resource path, leading to broken images or unexpected requests.
- Standards compliance: The URL Living Standard and RFC 3986 define strict rules for percent-encoding. Invalid URLs violate these standards.
- Reliability: Proxies, CDNs, and server-side software may reject or misroute requests with malformed URLs, causing images to fail to load in certain environments even if they work in your local browser.
How to fix it
- Find every bare
%in the URL that isn't followed by two hexadecimal digits. - If the
%is meant as a literal percent sign, replace it with%25. - If the
%is part of a broken encoding sequence (e.g.,%2or%GH), correct it to the intended two-digit hex code (e.g.,%20for a space). - Use proper URL encoding functions in your language or framework (e.g.,
encodeURIComponent()in JavaScript,urlencode()in PHP) when building URLs dynamically, rather than constructing them by hand.
Examples
Literal percent sign not encoded
<!-- ❌ Bad: bare "%" is not followed by two hex digits -->
<imgalt="Chart"src="https://example.com/chart.png?scale=50%">
<!-- ✅ Fixed: "%" encoded as "%25" -->
<imgalt="Chart"src="https://example.com/chart.png?scale=50%25">
Incomplete percent-encoding sequence
<!-- ❌ Bad: "%2" is incomplete — missing the second hex digit -->
<imgalt="Photo"src="https://example.com/my%2photo.jpg">
<!-- ✅ Fixed: use "%20" for a space character -->
<imgalt="Photo"src="https://example.com/my%20photo.jpg">
Non-hexadecimal characters after percent sign
<!-- ❌ Bad: "%zz" uses non-hex characters -->
<imgalt="Logo"src="https://example.com/logo%zz.png">
<!-- ✅ Fixed: remove the erroneous sequence if it was unintentional -->
<imgalt="Logo"src="https://example.com/logo.png">
Multiple encoding issues in one URL
<!-- ❌ Bad: bare "%" in query value and unencoded space -->
<imgalt="Report"src="https://example.com/img?label=100%&name=my file.png">
<!-- ✅ Fixed: "%" → "%25", space → "%20" -->
<imgalt="Report"src="https://example.com/img?label=100%25&name=my%20file.png">
Building URLs safely with JavaScript
When generating src values in code, use encodeURIComponent() to handle special characters automatically:
constlabel="100%";
constname="my file.png";
constsrc=`https://example.com/img?label=${encodeURIComponent(label)}&name=${encodeURIComponent(name)}`;
// Result: "https://example.com/img?label=100%25&name=my%20file.png"
This ensures every special character — including % — is correctly percent-encoded without manual effort.
The HTML specification requires that URL attributes like src contain valid URLs. While browsers are generally forgiving and may strip or ignore whitespace characters in URLs, including tabs (\t), newlines (\n), or carriage returns (\r) inside a src value is technically invalid. These characters are not legal within a URL according to both the HTML and URL standards.
Beyond standards compliance, there are practical reasons to fix this:
- Unpredictable behavior: Different browsers may handle embedded whitespace differently. Some might silently strip it, while others could encode it as
%0Aor%0D, leading to broken image requests. - Debugging difficulty: Invisible characters make URLs fail silently. The path looks correct in your editor, but the actual HTTP request goes to a different (malformed) URL.
- Accessibility and tooling: Screen readers, crawlers, and other tools that parse your HTML may not handle malformed URLs gracefully, potentially causing images to be skipped or reported as broken.
Common Causes
This issue typically appears in a few scenarios:
- Multi-line attributes in templates: When a URL is built dynamically in a template engine (e.g., PHP, Jinja, Handlebars), line breaks in the template code can leak into the rendered attribute value.
- Copy-paste errors: Copying a URL from a document, email, or another source may include hidden line breaks or tab characters.
- Code formatting: Some developers or auto-formatters may break long attribute values across multiple lines, inadvertently injecting newlines into the value.
- String concatenation: Building URLs through string concatenation in server-side code can introduce whitespace if variables contain trailing newlines.
Examples
Incorrect: Newline inside src value
The newline before the closing quote makes this an invalid URL:
<imgsrc="images/photo.jpg "alt="A scenic photo">
Incorrect: Tab character in src value
A tab character embedded in the middle of the URL path:
<imgsrc="images/ photo.jpg"alt="A scenic photo">
Incorrect: Multi-line URL from template output
This can happen when a template engine outputs a URL with leading or trailing whitespace:
<imgsrc=" https://example.com/images/photo.jpg "alt="A scenic photo">
https://example.com/images/photo.jpg
Correct: Clean, single-line src value
The URL is a single continuous string with no tabs, newlines, or carriage returns:
<imgsrc="images/photo.jpg"alt="A scenic photo">
Correct: Long URL kept on one line
Even if the URL is long, it must remain on a single line without breaks:
<imgsrc="https://cdn.example.com/assets/images/2024/photos/scenic-landscape-full-resolution.jpg"alt="A scenic photo">
How to Fix It
- Inspect the attribute value: Open the raw HTML source (not the rendered page) and look at the
srcvalue character by character. Use your editor's "show whitespace" or "show invisible characters" feature to reveal hidden tabs and line breaks. - Remove all whitespace inside the URL: Ensure the entire URL is on a single line with no tabs, newlines, or carriage returns anywhere between the opening and closing quotes.
- Check your templates: If the URL is generated dynamically, trim the output. Most languages offer a
trim()orstrip()function that removes leading and trailing whitespace including newlines. - Lint your HTML: Use the W3C validator or an HTML linter in your build pipeline to catch these issues automatically before deployment.
URLs follow strict syntax rules defined by RFC 3986, which does not permit literal space characters anywhere in the URI — including path segments, query strings, and fragment identifiers. When the W3C HTML Validator encounters a space in the src attribute of a <script> element, it flags it as an illegal character because the attribute value is not a valid URL.
While most modern browsers will silently fix this by encoding the space before making the request, relying on this behavior is problematic for several reasons:
- Standards compliance: The HTML specification requires that the
srcattribute contain a valid URL. A URL with a literal space is technically malformed. - Cross-browser reliability: Not all user agents, proxies, or CDNs handle malformed URLs the same way. What works in one browser may fail in another context.
- Interoperability: Other tools that consume your HTML — such as linters, crawlers, screen readers, and build pipelines — may not be as forgiving as browsers.
- Copy-paste and linking issues: Literal spaces in URLs cause problems when users copy links or when URLs appear in plain-text contexts like emails, where the space may break the URL in two.
How to fix it
You have three options, listed from most recommended to least:
- Rename the file or directory to eliminate spaces entirely (e.g., use hyphens or underscores). This is the cleanest solution.
- Percent-encode the space as
%20in thesrcattribute value. - Use a build tool or bundler that generates references with properly encoded or space-free paths automatically.
Avoid using + as a space replacement in path segments. The + character represents a space only in application/x-www-form-urlencoded query strings, not in URL path segments.
Examples
❌ Invalid: space in the path segment
<scriptsrc="https://example.com/media assets/app.js"></script>
The space between media and assets makes this an invalid URL.
✅ Fixed: percent-encode the space
<scriptsrc="https://example.com/media%20assets/app.js"></script>
Replacing the space with %20 produces a valid, standards-compliant URL.
✅ Better: rename to avoid spaces entirely
<scriptsrc="https://example.com/media-assets/app.js"></script>
Using a hyphen (or underscore) instead of a space is the preferred approach. It keeps URLs clean, readable, and free of encoding issues.
❌ Invalid: space in a local relative path
This issue isn't limited to absolute URLs. Relative paths trigger the same error:
<scriptsrc="js/my script.js"></script>
✅ Fixed: encode or rename the local file
<scriptsrc="js/my%20script.js"></script>
Or, better yet:
<scriptsrc="js/my-script.js"></script>
Multiple spaces and other special characters
If a URL contains multiple spaces or other special characters, each one must be individually encoded. For example, { becomes %7B and } becomes %7D. A quick reference for common characters:
| Character | Encoded form |
|---|---|
| Space | %20 |
[ | %5B |
] | %5D |
{ | %7B |
} | %7D |
<!-- Invalid -->
<scriptsrc="libs/my library [v2].js"></script>
<!-- Valid -->
<scriptsrc="libs/my%20library%20%5Bv2%5D.js"></script>
<!-- Best: rename the file -->
<scriptsrc="libs/my-library-v2.js"></script>
Note that this same rule applies to the src attribute on other elements like <img>, <iframe>, <audio>, and <video>, as well as the href attribute on <a> and <link>. Whenever you reference a URL in HTML, make sure it contains no literal spaces.
When the browser's HTML parser encounters a src attribute, it expects the value between the opening and closing quotes to be a valid URL. URLs have strict rules about which characters are permitted — a literal double quote (") is not one of them. If a " character appears inside the URL, the validator flags it as an illegal character in the query string (or other parts of the URL).
This error often doesn't stem from an intentionally embedded quote in the URL itself. Instead, it's usually a symptom of malformed HTML around the attribute. Common causes include:
- Stray quotes after the attribute value, such as writing
src="https://example.com/script.js"async""instead of properly separating attributes. - Accidentally doubled closing quotes, like
src="https://example.com/script.js"". - Boolean attributes given empty-string values incorrectly, such as
async""instead of justasync, which causes the parser to interpret the extra quotes as part of the precedingsrcvalue. - Copy-paste errors that introduce smart quotes (
"") or extra quotation marks into the URL.
This matters for several reasons. Malformed src attributes can cause the script to fail to load entirely, breaking functionality on your page. It also violates the HTML specification, which can lead to unpredictable behavior across different browsers as each parser tries to recover from the error differently.
To fix the issue, carefully inspect the <script> tag and ensure that:
- The
srcattribute value contains only a valid URL with no unescaped"characters. - The opening and closing quotes around the attribute value are properly balanced.
- Attributes are separated by whitespace — not jammed together.
- Boolean attributes like
asyncanddeferare written as bare keywords without values.
If you genuinely need a double quote character in a query string (which is rare), encode it as %22.
Examples
Incorrect — stray quotes between attributes
In this example, the async attribute is malformed as async"", which causes the parser to interpret the extra quotes as part of the src URL:
<scriptsrc="https://example.com/js/app.js?ver=3.1"async""></script>
Incorrect — doubled closing quote
Here, an extra " at the end of the src value creates an illegal character in the URL:
<scriptsrc="https://example.com/js/app.js?ver=3.1""></script>
Incorrect — smart quotes from copy-paste
Curly/smart quotes copied from a word processor are not valid HTML attribute delimiters and get treated as part of the URL:
<scriptsrc="https://example.com/js/app.js?ver=3.1"></script>
Correct — clean attributes with proper quoting
<scriptsrc="https://example.com/js/app.js?ver=3.1"async></script>
Correct — boolean attribute written as a bare keyword
Boolean attributes like async and defer don't need a value. Simply include the attribute name:
<scriptsrc="https://example.com/js/app.js?ver=3.1"defer></script>
While async="async" is technically valid per the spec, the cleanest and most common form is the bare attribute. Avoid empty-string patterns like async="" placed without proper spacing, as they can lead to the exact quoting errors described here.
Correct — full valid document
<!DOCTYPE html>
<htmllang="en">
<head>
<title>Valid Script Example</title>
<scriptsrc="https://example.com/js/app.js?ver=3.1"async></script>
</head>
<body>
<p>Page content here.</p>
</body>
</html>
If you're generating <script> tags dynamically (through a CMS, template engine, or build tool), check the template source rather than just the rendered output. The stray quotes are often introduced by incorrect string concatenation or escaping logic in the server-side code.
Spaces in the src attribute of a <source> element are not valid URL characters and must be encoded or removed.
URLs follow strict syntax rules defined in RFC 3986. A space character is not permitted in any part of a URL path. When a file name or path contains spaces, you must replace each space with %20 (the percent-encoded form) or rename the file to avoid spaces altogether.
This applies to all elements that accept a URL, including <source>, <img>, <a>, <script>, and <link>. Browsers often handle spaces gracefully by encoding them automatically, but the HTML is still technically invalid and can cause issues in some contexts, such as when URLs are copied, shared, or processed by other tools.
The best practice is to avoid spaces in file names entirely. Use hyphens (-) or underscores (_) instead. If you can't rename the files, percent-encode the spaces.
Bad Example
<videocontrols>
<sourcesrc="videos/my cool video.mp4"type="video/mp4">
</video>
Good Example — Percent-Encoded Spaces
<videocontrols>
<sourcesrc="videos/my%20cool%20video.mp4"type="video/mp4">
</video>
Good Example — No Spaces in File Name
<videocontrols>
<sourcesrc="videos/my-cool-video.mp4"type="video/mp4">
</video>
When the W3C HTML Validator reports "Expected a slash," it means the URL parser encountered an unexpected character where a / should appear. URLs follow a strict syntax defined by the URL Living Standard. For scheme-based URLs, the format requires the scheme (like https:) to be immediately followed by // and then the authority (hostname). Any deviation — such as a space, a missing slash, or an encoded character in the wrong place — will make the URL invalid.
This matters for several reasons. Browsers may attempt to correct malformed URLs, but their behavior is inconsistent and unpredictable. A broken src attribute can cause images not to load, scripts to fail silently, or media elements to show fallback content. Screen readers and assistive technologies rely on valid URLs to provide meaningful information to users. Search engine crawlers may also fail to follow or index resources with malformed URLs.
Common causes of this error include:
- Accidental spaces inserted within the URL, especially between the scheme and the double slashes (e.g.,
https: //instead ofhttps://). - Missing slashes in the scheme (e.g.,
https:/example.comwith only one slash). - Copy-paste artifacts where invisible characters or line breaks get embedded in the URL string.
- Template or CMS issues where dynamic URL generation introduces unexpected characters.
To fix the issue, carefully inspect the src attribute value and ensure it forms a valid, complete URL with no stray characters. If the URL is generated dynamically, check the code that constructs it.
Examples
Incorrect: space between scheme and slashes
<imgsrc="https: //example.com/photo.jpg"alt="A photo">
The space after https: breaks the URL. The validator expects a / immediately after the colon but finds a space instead.
Fixed: remove the space
<imgsrc="https://example.com/photo.jpg"alt="A photo">
Incorrect: single slash instead of double slash
<scriptsrc="https:/cdn.example.com/app.js"></script>
The URL scheme requires // after https:, but only one / is present.
Fixed: use the correct double slash
<scriptsrc="https://cdn.example.com/app.js"></script>
Incorrect: line break embedded in the URL
Sometimes copy-pasting or template rendering introduces hidden line breaks:
<videosrc="https:// example.com/video.mp4">
example.com/video.mp4
</video>
Fixed: ensure the URL is on a single line with no breaks
<videosrc="https://example.com/video.mp4"></video>
Incorrect: protocol-relative URL with a missing slash
<imgsrc="/example.com/logo.png"alt="Logo">
If the intent is a protocol-relative URL, it needs two slashes. With a single slash, this becomes an absolute path on the current domain rather than a reference to example.com.
Fixed: use two slashes for protocol-relative URLs
<imgsrc="//example.com/logo.png"alt="Logo">
Tip: If you're having trouble spotting the problem, paste the URL into your browser's address bar to see if it resolves correctly, or use a text editor that reveals invisible characters (like zero-width spaces or non-breaking spaces) that may be hiding in the string.
The srcset attribute allows you to provide the browser with a set of image sources to choose from based on the user's viewport size or display density. Each entry in srcset is called an image candidate string and consists of a URL followed by an optional descriptor — either a width descriptor (like 300w) or a pixel density descriptor (like 2x).
The sizes attribute tells the browser what display size the image will occupy at various viewport widths, using media conditions and length values. The browser uses this size information together with the width descriptors in srcset to select the most appropriate image. This is why the HTML specification requires that when sizes is present, all srcset entries must use width descriptors — without them, the browser cannot perform the size-based selection that sizes is designed to enable.
This error typically appears in three situations:
- A
srcsetentry has no descriptor at all — the URL is listed without any accompanying width or density value. - A pixel density descriptor (
x) is used alongsidesizes— mixingsizeswithxdescriptors is invalid because the two mechanisms are mutually exclusive. - A typo or formatting issue — for example, writing
600pxinstead of600w, or placing a comma incorrectly.
Why this matters
- Standards compliance: The WHATWG HTML Living Standard explicitly states that when
sizesis specified, all image candidates must use width descriptors. - Correct image selection: Without proper width descriptors, browsers cannot accurately determine which image to download. This may lead to unnecessarily large downloads on small screens or blurry images on large screens.
- Performance: Responsive images are a key performance optimization. A malformed
srcsetdefeats the purpose and can result in wasted bandwidth.
How to fix it
- Determine the intrinsic width (in pixels) of each image file listed in
srcset. - Append the width descriptor to each URL in the format
[width]w, where[width]is the image's actual pixel width. - Ensure no entries use
xdescriptors whensizesis present. If you need density descriptors, remove thesizesattribute entirely. - Make sure every entry has a descriptor — bare URLs without any descriptor are invalid when
sizesis used.
Examples
Missing width descriptor
This triggers the validation error because the srcset URL has no width descriptor:
<img
src="/img/photo.jpg"
srcset="/img/photo.jpg"
sizes="(max-width: 600px) 100vw, 600px"
alt="A sunset over the mountains"
>
Fixed by adding the width descriptor:
<img
src="/img/photo.jpg"
srcset="/img/photo.jpg 600w"
sizes="(max-width: 600px) 100vw, 600px"
alt="A sunset over the mountains"
>
Using pixel density descriptors with sizes
This is invalid because x descriptors cannot be combined with the sizes attribute:
<img
src="/img/photo.jpg"
srcset="/img/photo.jpg 1x, /img/photo-2x.jpg 2x"
sizes="(max-width: 800px) 100vw, 800px"
alt="A sunset over the mountains"
>
Fixed by switching to width descriptors:
<img
src="/img/photo.jpg"
srcset="/img/photo.jpg 800w, /img/photo-2x.jpg 1600w"
sizes="(max-width: 800px) 100vw, 800px"
alt="A sunset over the mountains"
>
Alternatively, if you only need density-based selection and don't need sizes, remove it:
<img
src="/img/photo.jpg"
srcset="/img/photo.jpg 1x, /img/photo-2x.jpg 2x"
alt="A sunset over the mountains"
>
Multiple image sources with width descriptors
A complete responsive image setup with several sizes:
<img
src="/img/photo-800.jpg"
srcset=" /img/photo-400.jpg 400w, /img/photo-800.jpg 800w, /img/photo-1200.jpg 1200w "
/img/photo-400.jpg 400w,
/img/photo-800.jpg 800w,
/img/photo-1200.jpg 1200w
sizes="(max-width: 480px) 100vw, (max-width: 960px) 50vw, 800px"
alt="A sunset over the mountains"
>
Each URL is paired with a w descriptor that matches the image's intrinsic pixel width. The sizes attribute then tells the browser how wide the image will display at each breakpoint, allowing it to pick the best candidate.
The srcset attribute allows you to specify multiple image sources so the browser can choose the most appropriate one based on the user's device characteristics, such as screen resolution or viewport width. When you include a srcset attribute on an <img> element, the HTML specification requires it to contain one or more comma-separated image candidate strings. Each string consists of a URL followed by an optional descriptor — either a width descriptor (e.g., 200w) or a pixel density descriptor (e.g., 2x).
This validation error typically appears when:
- The
srcsetattribute is empty (srcset="") - The
srcsetattribute contains only whitespace (srcset=" ") - The value contains syntax errors such as missing URLs, invalid descriptors, or incorrect formatting
- A templating engine or CMS outputs the attribute with no value
This matters because browsers rely on the srcset value to select the best image to load. An empty or malformed srcset means the browser must fall back entirely to the src attribute, making the srcset attribute pointless. Additionally, invalid markup can cause unexpected behavior across different browsers and undermines standards compliance.
How to fix it
- Provide valid image candidate strings. Each entry needs a URL and optionally a width or pixel density descriptor, with entries separated by commas.
- Remove the attribute entirely if you don't have multiple image sources to offer. A plain
srcattribute is perfectly fine on its own. - Check dynamic output. If a CMS or templating system generates the
srcset, ensure it conditionally omits the attribute when no responsive image candidates are available, rather than outputting an empty attribute.
Examples
❌ Empty srcset attribute
<imgsrc="/img/photo.jpg"alt="A sunset over the ocean"srcset="">
This triggers the error because srcset is present but contains no image candidate strings.
❌ Malformed srcset value
<imgsrc="/img/photo.jpg"alt="A sunset over the ocean"srcset="1x, 2x">
This is invalid because each candidate string must include a URL. Descriptors alone are not valid entries.
✅ Using pixel density descriptors
<img
src="/img/photo-400.jpg"
alt="A sunset over the ocean"
srcset=" /img/photo-400.jpg 1x, /img/photo-800.jpg 2x ">
/img/photo-400.jpg 1x,
/img/photo-800.jpg 2x
Each candidate string contains a URL followed by a pixel density descriptor (1x, 2x). The browser picks the best match for the user's display.
✅ Using width descriptors with sizes
<img
src="/img/photo-400.jpg"
alt="A sunset over the ocean"
srcset=" /img/photo-400.jpg 400w, /img/photo-800.jpg 800w, /img/photo-1200.jpg 1200w "
/img/photo-400.jpg 400w,
/img/photo-800.jpg 800w,
/img/photo-1200.jpg 1200w
sizes="(max-width: 600px) 400px, (max-width: 1000px) 800px, 1200px">
Width descriptors (e.g., 400w) tell the browser the intrinsic width of each image. The sizes attribute then tells the browser how large the image will be displayed at various viewport sizes, allowing it to calculate the best source to download.
✅ Removing srcset when not needed
<imgsrc="/img/photo.jpg"alt="A sunset over the ocean">
If you only have a single image source, simply omit srcset altogether. The src attribute alone is valid and sufficient.
✅ Single candidate in srcset
<img
src="/img/photo.jpg"
alt="A sunset over the ocean"
srcset="/img/photo-highres.jpg 2x">
Even a single image candidate string is valid. Here, the browser will use the high-resolution image on 2x displays and fall back to src otherwise.
The srcset attribute allows you to provide multiple image sources so the browser can choose the most appropriate one based on the user's viewport size or screen density. There are two distinct modes for srcset:
- Width descriptor mode — each candidate specifies its intrinsic width using a
wdescriptor (e.g.,400w). This mode requires thesizesattribute so the browser knows how much space the image will occupy in the layout and can calculate which source to download. - Pixel density descriptor mode — each candidate specifies a pixel density using an
xdescriptor (e.g.,2x). This mode must not include asizesattribute.
When you include a sizes attribute but forget to add width descriptors to one or more srcset entries, the browser has incomplete information. The HTML specification explicitly states that if sizes is present, all image candidate strings must use width descriptors. An entry without a descriptor defaults to 1x (a pixel density descriptor), which conflicts with the width descriptor mode triggered by sizes. This mismatch causes the W3C validator to report the error.
Beyond validation, this matters for real-world performance. Responsive images are one of the most effective tools for reducing page weight on smaller screens. If the descriptors are missing or mismatched, browsers may download an image that is too large or too small, hurting both performance and visual quality.
How to fix it
You have two options depending on your use case:
Option 1: Add width descriptors to all srcset candidates
If you need the browser to select images based on viewport size (the most common responsive images pattern), keep the sizes attribute and ensure every srcset entry has a w descriptor that matches the image's intrinsic pixel width.
Option 2: Remove sizes and use pixel density descriptors
If you only need to serve higher-resolution images for high-DPI screens (e.g., Retina displays) and the image always renders at the same CSS size, remove the sizes attribute and use x descriptors instead.
Examples
❌ Incorrect: sizes present but srcset entry has no width descriptor
<img
src="photo-800.jpg"
srcset="photo-400.jpg, photo-800.jpg"
sizes="(min-width: 600px) 800px, 100vw"
alt="A mountain landscape">
Both srcset entries lack a width descriptor. Because sizes is present, the validator reports an error for each candidate.
✅ Correct: sizes present with width descriptors on every candidate
<img
src="photo-800.jpg"
srcset="photo-400.jpg 400w, photo-800.jpg 800w"
sizes="(min-width: 600px) 800px, 100vw"
alt="A mountain landscape">
Each candidate now specifies its intrinsic width (400w and 800w), which tells the browser the actual pixel width of each source file. The browser combines this with the sizes value to pick the best match.
❌ Incorrect: mixing width descriptors and bare entries
<img
src="photo-800.jpg"
srcset="photo-400.jpg 400w, photo-800.jpg"
sizes="(min-width: 600px) 800px, 100vw"
alt="A mountain landscape">
The second candidate (photo-800.jpg) is missing its width descriptor. All candidates must have one when sizes is present — not just some of them.
✅ Correct: pixel density descriptors without sizes
<img
src="photo-800.jpg"
srcset="photo-800.jpg 1x, photo-1600.jpg 2x"
alt="A mountain landscape">
Here the sizes attribute is removed, and each srcset entry uses a pixel density descriptor (1x, 2x). This is valid and appropriate when the image always occupies the same CSS dimensions regardless of viewport width.
❌ Incorrect: using sizes with pixel density descriptors
<img
src="photo-800.jpg"
srcset="photo-800.jpg 1x, photo-1600.jpg 2x"
sizes="(min-width: 600px) 800px, 100vw"
alt="A mountain landscape">
The sizes attribute and x descriptors cannot be combined. Either switch to w descriptors or remove sizes.
Quick reference
| Pattern | srcset descriptor | sizes required? |
|---|---|---|
| Viewport-based selection | Width (w) | Yes |
| Density-based selection | Pixel density (x) | No — must be omitted |
Remember that the w value in srcset refers to the image file's intrinsic pixel width (e.g., an 800-pixel-wide image gets 800w), while values in sizes use CSS length units like px, vw, or em to describe how wide the image will render in the layout.
In URLs, percent-encoding is used to represent special or reserved characters. The format is a % sign followed by exactly two hexadecimal digits (0–9, A–F), such as %20 for a space or %3F for a question mark. When the browser encounters a % in a URL, it expects the next two characters to be valid hex digits. If they aren't — for example, % followed by a letter like G, a non-hex character, or nothing at all — the URL is considered malformed.
This issue specifically targets the srcset attribute on <source> elements (commonly used inside <picture> elements), where one or more image candidate URLs contain an invalid percent sequence. The most common causes are:
- A literal
%sign in a query parameter — e.g.,?quality=80%where%is meant literally but isn't encoded. - Truncated percent-encoding — e.g.,
%2instead of%2F, possibly from a copy-paste error or a broken URL-encoding function. - Double-encoding gone wrong — a URL that was partially encoded, leaving some
%characters in an ambiguous state.
This matters because browsers may handle malformed URLs inconsistently. Some browsers might try to recover gracefully, while others may fail to load the image entirely. Invalid URLs also break standards compliance, can cause issues with CDNs and caching layers, and make your markup unreliable across different environments.
How to fix it
- Find the offending
%character in yoursrcsetURL. - If the
%is meant literally (e.g., as part of a percentage value like80%), encode it as%25. - If the
%is part of an incomplete percent-encoding (e.g.,%2instead of%2F), correct it to the full three-character sequence. - Review your URL-generation logic — if URLs are built dynamically by a CMS, template engine, or server-side code, ensure proper encoding is applied before output.
Examples
Invalid: literal % in srcset URL
The % in quality=80% is not followed by two hex digits, so it's treated as a broken percent-encoding sequence.
<picture>
<source
srcset="https://example.com/photo.webp?quality=80%"
type="image/webp">
<imgsrc="https://example.com/photo.jpg"alt="A scenic landscape">
</picture>
Valid: % encoded as %25
Replacing the bare % with %25 produces a valid URL.
<picture>
<source
srcset="https://example.com/photo.webp?quality=80%25"
type="image/webp">
<imgsrc="https://example.com/photo.jpg"alt="A scenic landscape">
</picture>
Invalid: truncated percent-encoding in a file path
Here, %2 is incomplete — it should be %2F (which decodes to /) or some other valid sequence.
<picture>
<source
srcset="https://example.com/images%2photo.webp 1x"
type="image/webp">
<imgsrc="https://example.com/photo.jpg"alt="Product photo">
</picture>
Valid: corrected percent-encoding
The sequence is now %2F, a properly formed encoding.
<picture>
<source
srcset="https://example.com/images%2Fphoto.webp 1x"
type="image/webp">
<imgsrc="https://example.com/photo.jpg"alt="Product photo">
</picture>
Invalid: unencoded % in srcset with multiple candidates
Every URL in the srcset list must be valid. Here, both candidates contain a bare %.
<picture>
<source
srcset="https://example.com/img.webp?w=480&q=75% 480w, https://example.com/img.webp?w=800&q=75% 800w"
https://example.com/img.webp?w=800&q=75% 800w
type="image/webp">
<imgsrc="https://example.com/img.jpg"alt="Blog header image">
</picture>
Valid: all candidates properly encoded
<picture>
<source
srcset="https://example.com/img.webp?w=480&q=75%25 480w, https://example.com/img.webp?w=800&q=75%25 800w"
https://example.com/img.webp?w=800&q=75%25 800w
type="image/webp">
<imgsrc="https://example.com/img.jpg"alt="Blog header image">
</picture>
Note that in the corrected example, & is also encoded as & within the HTML attribute, which is required for valid markup when using ampersands in attribute values.
A srcset attribute on a <source> element inside a <picture> requires each image URL to be paired with a width descriptor (w) or a pixel density descriptor (x).
The srcset attribute differs from the src attribute. While src accepts a bare URL, srcset expects one or more image candidates, where each candidate is a URL followed by a space and a descriptor. When no descriptor is provided, the W3C validator rejects the value because it cannot determine how the browser should select the image.
A width descriptor like 600w tells the browser the intrinsic width of the image in pixels. A pixel density descriptor like 1x or 2x indicates the intended display density. If you only have a single image and don't need responsive selection, you can still satisfy the validator by appending a descriptor.
When <source> is used inside <picture>, the srcset attribute is required instead of src. This is defined in the HTML specification: the <source> element within <picture> does not support src.
Invalid example
<picture>
<sourcetype="image/webp"srcset="/images/img01.webp">
<imgsrc="/images/img01.jpg"alt="A sample image"width="600"height="400">
</picture>
Valid examples
Add a width descriptor to each entry in srcset:
<picture>
<source
type="image/webp"
srcset="/images/img01-600.webp 600w, /images/img01-1200.webp 1200w"
sizes="(max-width: 600px) 100vw, 600px">
<imgsrc="/images/img01.jpg"alt="A sample image"width="600"height="400">
</picture>
If you have a single image and no responsive variants, use a pixel density descriptor:
<picture>
<sourcetype="image/webp"srcset="/images/img01.webp 1x">
<imgsrc="/images/img01.jpg"alt="A sample image"width="600"height="400">
</picture>
The srcset attribute lets browsers intelligently choose which image to load based on the viewport size and device pixel ratio. Each entry in a srcset consists of a URL followed by either a width descriptor (like 300w) or a pixel density descriptor (like 2x). When using width descriptors, the value represents the intrinsic pixel width of the image file — that is, the actual width of the image as stored on disk.
A width descriptor of 0w violates the HTML specification, which requires width descriptors to be integers greater than zero. A zero-width image cannot meaningfully participate in the browser's source selection process. The browser uses these width values in combination with the sizes attribute to calculate which image best fits the current layout — a value of zero would break this calculation entirely.
This issue commonly occurs when:
- Image dimensions are dynamically generated and a fallback of
0is used for missing data. - A placeholder or empty state is accidentally included in the
srcset. - A CMS or build tool outputs a
0wdescriptor for images whose dimensions weren't computed.
Why it matters
- Standards compliance: The HTML specification explicitly requires width descriptors to be positive integers. Validators will flag
0was an error. - Browser behavior: While browsers may silently ignore the invalid entry, you can't rely on consistent handling across all browsers and versions. The image selection algorithm may behave unpredictably.
- Performance: A well-formed
srcsetis key to responsive image loading. Invalid descriptors can prevent browsers from selecting the optimal image, leading to unnecessarily large downloads or poor image quality.
How to fix it
- Open the image file associated with the
0wdescriptor and check its actual pixel width using an image editor or the command line. - Replace
0wwith the correct width (e.g.,150wfor a 150-pixel-wide image). - If the image is truly zero-width or a placeholder, remove that entry from the
srcsetentirely. - Ensure every remaining entry has a unique, positive width descriptor.
Examples
❌ Invalid: width descriptor of 0w
<picture>
<source
srcset="/images/icon_placeholder.png 0w, /images/icon_large.png 600w"
/images/icon_large.png 600w
media="(max-width: 600px)">
<imgsrc="/images/icon_fallback.png"alt="App logo">
</picture>
The 0w descriptor triggers the validation error because zero is not a valid width.
✅ Fixed: all width descriptors are positive
<picture>
<source
srcset="/images/icon_small.png 300w, /images/icon_large.png 600w"
/images/icon_large.png 600w
media="(max-width: 600px)">
<imgsrc="/images/icon_fallback.png"alt="App logo">
</picture>
Each entry now has a meaningful width descriptor (300w and 600w) that reflects the actual pixel width of the corresponding image.
❌ Invalid: 0w on an <img> element
<img
srcset="/images/hero_tiny.jpg 0w, /images/hero_medium.jpg 800w, /images/hero_large.jpg 1200w"
/images/hero_medium.jpg 800w,
/images/hero_large.jpg 1200w
sizes="100vw"
src="/images/hero_medium.jpg"
alt="Mountain landscape">
✅ Fixed: placeholder entry removed or corrected
If the tiny image is 400 pixels wide, use 400w:
<img
srcset="/images/hero_tiny.jpg 400w, /images/hero_medium.jpg 800w, /images/hero_large.jpg 1200w"
/images/hero_medium.jpg 800w,
/images/hero_large.jpg 1200w
sizes="100vw"
src="/images/hero_medium.jpg"
alt="Mountain landscape">
Alternatively, if the image doesn't belong in the set at all, simply remove it:
<img
srcset="/images/hero_medium.jpg 800w, /images/hero_large.jpg 1200w"
/images/hero_large.jpg 1200w
sizes="100vw"
src="/images/hero_medium.jpg"
alt="Mountain landscape">
When using a build tool or CMS that generates srcset values dynamically, add a check to filter out any entries where the computed width is zero or missing before rendering the attribute. This prevents the invalid markup from reaching production.
The <source> element is used inside <picture>, <audio>, or <video> elements to specify alternative media resources. When used inside a <picture> element, the srcset attribute is required and must contain one or more comma-separated image candidate strings. Each image candidate string consists of a URL and an optional descriptor — either a width descriptor like 400w or a pixel density descriptor like 2x.
This validation error typically occurs when:
- The
srcsetattribute is present but empty (srcset=""). - The attribute value contains only whitespace.
- The value is malformed or contains syntax errors (e.g., missing URLs, invalid descriptors).
- A dynamic templating system or CMS outputs the attribute with no value.
Why this matters
Browsers rely on the srcset attribute to select the most appropriate image to display based on the user's device capabilities, viewport size, and network conditions. An empty or invalid srcset means the browser cannot perform this selection, potentially resulting in no image being displayed at all. This degrades the user experience, harms accessibility (screen readers and assistive technologies may encounter unexpected behavior), and violates the HTML specification as defined by the WHATWG living standard.
How to fix it
- Provide at least one valid image URL in the
srcsetattribute. - Optionally add descriptors — use width descriptors (
w) when combined with thesizesattribute, or pixel density descriptors (x) for fixed-size images. - If you have no image to provide, remove the
<source>element entirely rather than leavingsrcsetempty. - Check dynamic output — if a CMS or templating engine generates the
srcsetvalue, add a conditional check to omit the<source>element when no images are available.
Examples
❌ Empty srcset attribute
<picture>
<sourcesrcset=""type="image/webp">
<imgsrc="photo.jpg"alt="A sunset over the ocean">
</picture>
This triggers the error because srcset is present but contains no image candidate strings.
❌ Invalid descriptor syntax
<picture>
<sourcesrcset="photo.webp 400"type="image/webp">
<imgsrc="photo.jpg"alt="A sunset over the ocean">
</picture>
This is invalid because 400 is not a recognized descriptor — it must be 400w or a density descriptor like 2x.
✅ Single image candidate
<picture>
<sourcesrcset="photo.webp"type="image/webp">
<imgsrc="photo.jpg"alt="A sunset over the ocean">
</picture>
A single URL without a descriptor is valid and serves as the default 1x candidate.
✅ Multiple candidates with width descriptors
<picture>
<source
srcset="photo-small.webp 400w, photo-medium.webp 800w, photo-large.webp 1200w"
sizes="(max-width: 600px) 400px, (max-width: 1000px) 800px, 1200px"
type="image/webp">
<imgsrc="photo.jpg"alt="A sunset over the ocean">
</picture>
This provides three image candidates with width descriptors, allowing the browser to choose the best match based on the viewport and display density.
✅ Multiple candidates with pixel density descriptors
<picture>
<sourcesrcset="photo.webp 1x, photo-2x.webp 2x"type="image/webp">
<imgsrc="photo.jpg"alt="A sunset over the ocean">
</picture>
Pixel density descriptors tell the browser which image to use based on the device's pixel ratio — 1x for standard displays and 2x for high-DPI (Retina) screens.
✅ Removing the source element when no image is available
If your application dynamically generates the srcset value and sometimes has no image to provide, omit the <source> element entirely:
<picture>
<imgsrc="photo.jpg"alt="A sunset over the ocean">
</picture>
This is valid because the <img> element inside <picture> serves as the required fallback and can stand alone.
The srcset attribute supports two types of descriptors: width descriptors (e.g., 480w) and pixel density descriptors (e.g., 2x). These two types cannot be mixed, and the sizes attribute is specifically designed to work with width descriptors. The sizes attribute tells the browser how wide the image will be displayed at various viewport sizes, so the browser can then pick the best image from srcset based on the widths you've provided. If any candidate in srcset lacks a width descriptor — or uses a density descriptor instead — the browser can't perform this calculation, and the HTML is invalid.
This matters for several reasons. First, browsers rely on the combination of sizes and width descriptors to make intelligent decisions about which image to download before the layout is computed. An invalid srcset can lead to the browser ignoring the entire attribute or selecting a suboptimal image, wasting bandwidth or displaying a blurry result. Second, standards compliance ensures consistent behavior across all browsers and devices.
A common mistake is specifying sizes while using density descriptors (1x, 2x) or providing bare URLs without any descriptor in srcset. If you want to use density descriptors, simply remove the sizes attribute. If you want responsive image selection based on viewport width, use width descriptors for every candidate.
Examples
Incorrect: Using density descriptors with sizes
<picture>
<source
srcset="image-small.jpg 1x, image-large.jpg 2x"
sizes="(max-width: 600px) 100vw, 50vw">
<imgsrc="image-small.jpg"alt="A landscape photo">
</picture>
This triggers the error because 1x and 2x are density descriptors, but the sizes attribute requires width descriptors.
Incorrect: Missing descriptor on one candidate
<picture>
<source
srcset="image-small.jpg, image-large.jpg 800w"
sizes="(max-width: 600px) 100vw, 50vw">
<imgsrc="image-small.jpg"alt="A landscape photo">
</picture>
Here, image-small.jpg has no descriptor at all. When sizes is present, every candidate must have a width descriptor.
Correct: All candidates use width descriptors with sizes
<picture>
<source
srcset="image-small.jpg 400w, image-large.jpg 800w"
sizes="(max-width: 600px) 100vw, 50vw">
<imgsrc="image-small.jpg"alt="A landscape photo">
</picture>
Each image candidate now specifies a width descriptor (400w, 800w), which matches the requirement imposed by the sizes attribute.
Correct: Using density descriptors without sizes
If you only need density-based selection (e.g., for retina displays) and don't need viewport-based sizing, remove the sizes attribute entirely:
<picture>
<sourcesrcset="image-small.jpg 1x, image-large.jpg 2x">
<imgsrc="image-small.jpg"alt="A landscape photo">
</picture>
Correct: Using srcset with width descriptors on <img>
The same rules apply when using srcset directly on an <img> element:
<img
srcset="photo-320.jpg 320w, photo-640.jpg 640w, photo-1024.jpg 1024w"
sizes="(max-width: 600px) 100vw, (max-width: 1200px) 50vw, 33vw"
src="photo-640.jpg"
alt="A mountain landscape">
Every candidate in srcset includes a width descriptor, making this fully valid alongside the sizes attribute. The src attribute serves as the fallback for browsers that don't support srcset.
The target attribute specifies where to display the linked resource. The HTML specification defines a set of reserved keywords that all begin with an underscore: _blank, _self, _parent, and _top. Any other value starting with an underscore is considered invalid because the underscore prefix is reserved for current and future keywords defined by the specification.
This matters for several reasons. First, browsers may handle unrecognized underscore-prefixed values inconsistently — some might treat them like _blank, while others might ignore them entirely or treat them as named browsing contexts. This leads to unpredictable behavior across different browsers. Second, using reserved but undefined keywords signals a likely typo or misunderstanding of the attribute, which could cause navigation to behave differently than intended. Standards compliance ensures your links work reliably for all users.
The valid keywords and their meanings are:
_self— Opens the link in the current browsing context (the default behavior)._blank— Opens the link in a new, unnamed browsing context (typically a new tab)._parent— Opens the link in the parent browsing context, or_selfif there is no parent._top— Opens the link in the topmost browsing context, or_selfif there is no ancestor.
If you need to target a specific named frame or window, simply use a name without a leading underscore. Any string that doesn't start with _ is treated as a valid named browsing context.
Examples
Incorrect: Invalid reserved keyword
These examples use underscore-prefixed values that are not recognized keywords:
<!-- Typo: "_blanks" is not a valid keyword -->
<ahref="https://example.com"target="_blanks">Example</a>
<!-- "_new" is not a valid keyword -->
<ahref="https://example.com"target="_new">Open in new tab</a>
<!-- "_tab" is not a valid keyword -->
<ahref="https://example.com"target="_tab">Open link</a>
Correct: Using a valid keyword
<!-- Use "_blank" to open in a new tab -->
<ahref="https://example.com"target="_blank">Example</a>
<!-- Use "_self" to open in the same tab (also the default) -->
<ahref="https://example.com"target="_self">Example</a>
<!-- Use "_parent" to open in the parent frame -->
<ahref="https://example.com"target="_parent">Example</a>
<!-- Use "_top" to open in the topmost frame -->
<ahref="https://example.com"target="_top">Example</a>
Correct: Using a custom named browsing context
If you intend to target a specific named window or frame rather than using a keyword, remove the underscore prefix:
<!-- Valid: "myframe" is a custom browsing context name -->
<ahref="https://example.com"target="myframe">Open in myframe</a>
<!-- Valid: targeting a named iframe -->
<iframename="content-frame"src="about:blank"></iframe>
<ahref="https://example.com"target="content-frame">Load in iframe</a>
A common mistake is using _new with the intention of opening a link in a new tab. While some browsers may treat _new similarly to _blank, it is not a valid keyword. Use _blank instead. Note that when using target="_blank", it's a good security practice to also include rel="noopener" (though modern browsers now do this by default):
<ahref="https://example.com"target="_blank"rel="noopener">Example</a>
The type attribute on an <a> element is an advisory hint that tells the browser what media type (MIME type) to expect at the linked resource. A valid MIME type follows a strict format: a type, a / separator, and a subtype (e.g., text/html, application/pdf, image/png). Each part must consist of token characters — letters, digits, and certain symbols — but not spaces.
This validation error occurs when the MIME type value contains a space or other unexpected character in a position where only token characters or a / are allowed. Common causes include:
- Accidental spaces within the MIME type (e.g.,
application/ pdforapplication /pdf). - Multiple MIME types separated by spaces (e.g.,
text/html text/plain), which is not valid since the attribute accepts only a single MIME type. - Typos or copy-paste errors that introduce whitespace or non-token characters.
While the type attribute is purely advisory and browsers won't refuse to follow a link based on it, an invalid value defeats its purpose and signals sloppy markup. Standards-compliant HTML ensures your pages are interpreted consistently and avoids confusing tools, screen readers, or other user agents that may parse this attribute.
Examples
Incorrect: Space within the MIME type
<ahref="report.pdf"type="application/ pdf">Download Report</a>
The space after the / makes this an invalid MIME type.
Incorrect: Multiple MIME types separated by a space
<ahref="data.csv"type="text/csv text/plain">Download Data</a>
The type attribute only accepts a single MIME type. The space between text/csv and text/plain triggers the error.
Incorrect: Leading or trailing spaces
<ahref="photo.jpg"type=" image/jpeg ">View Photo</a>
Spaces before or after the MIME type are not permitted.
Correct: Valid MIME type with no spaces
<ahref="report.pdf"type="application/pdf">Download Report</a>
Correct: Other common valid MIME types
<ahref="data.csv"type="text/csv">Download Data</a>
<ahref="photo.jpg"type="image/jpeg">View Photo</a>
<ahref="archive.zip"type="application/zip">Download Archive</a>
Correct: MIME type with a parameter
MIME types can include parameters separated by a semicolon — no spaces are required, though a single space after the semicolon is permitted per the MIME specification:
<ahref="page.html"type="text/html; charset=utf-8">View Page</a>
How to Fix
- Inspect the
typevalue — look for any spaces within the type or subtype portions (before or after the/). - Remove extra spaces — ensure the value is a single, properly formatted MIME type like
type/subtype. - Use only one MIME type — if you've listed multiple types, pick the one that accurately describes the linked resource.
- Verify the MIME type is valid — consult the IANA Media Types registry to confirm you're using a recognized type.
- Consider removing the attribute — since
typeis purely advisory on<a>elements, if you're unsure of the correct MIME type, omitting the attribute entirely is perfectly valid.
A MIME type (also called a media type) always follows the format type/subtype, such as text/html, application/pdf, or image/jpeg. The "type" part indicates the general category (e.g., text, image, application, audio, video), and the "subtype" specifies the exact format within that category. When the validator reports "Subtype missing," it means the value you provided either lacks the /subtype portion or isn't a valid MIME type structure at all.
A common cause of this error is misunderstanding the purpose of the type attribute on <a> elements. The type attribute is not used to change the behavior or appearance of the link (the way type works on <input> or <button> elements). Instead, it serves as an advisory hint to the browser about what kind of resource the link points to. The browser may use this information to adjust its UI — for example, showing a download prompt for application/pdf — but it is not required to act on it.
Because of this misunderstanding, developers sometimes write type="button" on an <a> element, thinking it will make the link behave like a button. The value button is not a valid MIME type (it has no subtype), so the validator flags it. If you need a button, use a <button> element instead. If you need a styled link that looks like a button, keep the <a> element and use CSS for styling.
Why this matters
- Standards compliance: The HTML specification requires the
typeattribute on<a>to be a valid MIME type string. An invalid value violates the spec and may be ignored by browsers or cause unexpected behavior. - Accessibility and semantics: Using
type="button"on a link can create confusion about the element's role. Screen readers and assistive technologies rely on correct semantics to convey meaning to users. - Browser behavior: While browsers are generally forgiving, an invalid
typevalue provides no useful information and could interfere with how the browser handles the linked resource.
How to fix it
- If you intended to hint at the linked resource's MIME type, make sure you provide a complete
type/subtypevalue — for example,application/pdfrather than justapplication. - If you used
typeto try to style or change the link's behavior, remove thetypeattribute entirely. Use CSS for visual styling or switch to a more appropriate element like<button>. - If you don't need the
typeattribute, simply remove it. It's entirely optional on<a>elements.
Examples
Incorrect: missing subtype
<ahref="report.pdf"type="application">Download report</a>
The value application is incomplete — it's missing the subtype portion after the slash.
Incorrect: not a MIME type at all
<ahref="/order.php"type="button">Submit</a>
The value button is not a MIME type. This often stems from confusing the type attribute on <a> with the type attribute on <input> or <button>.
Correct: valid MIME type
<ahref="report.pdf"type="application/pdf">Download report</a>
<ahref="photo.jpeg"type="image/jpeg">See a photo</a>
The type attribute uses a properly formatted MIME type with both a type and subtype.
Correct: removing the attribute entirely
<ahref="/order.php">Submit</a>
If the type attribute isn't serving a real purpose, the simplest fix is to remove it.
Correct: using a button element instead
<buttontype="submit">Submit</button>
If you need actual button behavior (such as submitting a form), use a <button> element rather than an <a> element with an invalid type.
The type attribute on a <link> element specifies the MIME type of the linked resource. MIME types follow a specific format: a type and subtype separated by a single forward slash, like text/css, image/png, or application/json. They never contain the :// sequence found in URLs.
This error most commonly occurs when a URL is accidentally placed in the type attribute instead of in the href attribute, or when the attributes are confused with one another. For example, writing type="https://example.com/style.css" triggers this error because the validator encounters the colon in https: where it expects a valid MIME type token.
Another common cause is copying type values from other contexts (such as XML namespaces or schema references) that use URL-like strings, and mistakenly applying them to the type attribute.
Why this matters
- Standards compliance: The HTML specification requires the
typeattribute to contain a valid MIME type. Invalid values violate the spec and may cause browsers to misinterpret or ignore the linked resource. - Browser behavior: Browsers use the
typeattribute as a hint for how to handle the resource. An invalid MIME type could lead the browser to skip loading the resource entirely, causing missing styles, icons, or other assets. - Maintainability: Incorrect attribute values signal to other developers (and automated tools) that something is misconfigured, making the code harder to maintain.
How to fix it
- Check that
typecontains a valid MIME type, not a URL or other string. Common valid values includetext/css,image/png,image/x-icon,image/svg+xml, andapplication/rss+xml. - Ensure URLs are in the
hrefattribute, nottype. - Consider removing
typeentirely. For stylesheets, modern browsers default totext/css, sotype="text/css"is optional. For many use cases, thetypeattribute can be safely omitted.
Examples
❌ Incorrect: URL used as the type value
<linkrel="stylesheet"type="https://example.com/style.css">
The validator sees the colon in https: and reports the error because this is a URL, not a MIME type.
❌ Incorrect: Attributes swapped
<linkrel="icon"type="https://example.com/favicon.png"href="image/png">
Here the type and href values have been accidentally swapped.
✅ Correct: Valid MIME type with proper href
<linkrel="icon"type="image/png"href="https://example.com/favicon.png">
✅ Correct: Stylesheet with valid type
<linkrel="stylesheet"type="text/css"href="/css/style.css">
✅ Correct: Stylesheet without type (also valid)
<linkrel="stylesheet"href="/css/style.css">
Since browsers default to text/css for stylesheets, omitting type is perfectly valid and keeps your markup cleaner.
✅ Correct: RSS feed link
<linkrel="alternate"type="application/rss+xml"title="RSS Feed"href="/feed.xml">
A MIME type (also called a media type) is composed of two parts: a type and a subtype, separated by a forward slash (/) with no whitespace. For example, text/javascript has text as the type and javascript as the subtype. When you specify a value like text or javascript alone — without the slash and the other component — the validator reports this error because the subtype is missing.
This error commonly occurs when authors confuse the MIME type format with a simple label, writing something like type="text" or type="javascript" instead of the full type="text/javascript". It can also happen due to a typo, such as accidentally omitting the slash or the subtype portion.
Why this matters
Browsers rely on the type attribute to determine how to process the contents of a <script> element. An invalid MIME type can cause browsers to misinterpret or skip the script entirely. While modern browsers default to JavaScript when no type is specified, providing a malformed MIME type is not the same as omitting it — it may lead to unpredictable behavior across different browsers and versions. Keeping your markup valid also ensures better tooling support and forward compatibility.
How to fix it
You have two main options:
- Provide a complete, valid MIME type. For JavaScript, use
text/javascript. For JSON data blocks, useapplication/json. For importmaps, useimportmap. - Remove the
typeattribute entirely. Per the HTML specification, the default type for<script>istext/javascript, so omittingtypeis perfectly valid and is actually the recommended approach for standard JavaScript.
Examples
Incorrect: missing subtype
<!-- "text" alone is not a valid MIME type -->
<scripttype="text"src="app.js"></script>
<!-- "javascript" alone is not a valid MIME type -->
<scripttype="javascript"src="app.js"></script>
Correct: full MIME type specified
<scripttype="text/javascript"src="app.js"></script>
Correct: omitting the type attribute (recommended for JavaScript)
<scriptsrc="app.js"></script>
Since text/javascript is the default, omitting the attribute is the cleanest approach for standard JavaScript files.
Correct: using type for non-JavaScript purposes
The type attribute is still useful when embedding non-JavaScript content in a <script> element. In these cases, always use the full MIME type:
<scripttype="application/json"id="config">
{"apiUrl":"https://example.com/api"}
</script>
<scripttype="importmap">
{"imports":{"lodash":"/libs/lodash.js"}}
</script>
Common valid MIME types for <script>
| MIME Type | Purpose |
|---|---|
text/javascript | Standard JavaScript (default) |
module | JavaScript module |
importmap | Import map |
application/json | Embedded JSON data |
application/ld+json | Linked Data / structured data |
Note that module and importmap are special values defined by the HTML specification and are not traditional MIME types, but they are valid values for the type attribute on <script> elements.
The version attribute on the <svg> element is obsolete in SVG 2 and is no longer recognized as a valid attribute by the W3C HTML validator.
The version attribute was used in SVG 1.0 and SVG 1.1 to indicate which specification the SVG content conformed to, with values like "1.0" or "1.1". However, SVG 2 — which is the version used when SVG is embedded in HTML5 documents — dropped this attribute entirely. It never had any practical effect on how browsers rendered SVG content, so removing it is safe and has no impact on functionality.
Similarly, the baseProfile attribute and the xmlns:xlink namespace declaration are also obsolete when using inline SVG in HTML5. You can safely remove all three.
Bad Example
<svgversion="1.1"xmlns="http://www.w3.org/2000/svg"xmlns:xlink="http://www.w3.org/1999/xlink"width="100"height="100">
<circlecx="50"cy="50"r="40"fill="blue"/>
</svg>
Fixed Example
<svgxmlns="http://www.w3.org/2000/svg"width="100"height="100">
<circlecx="50"cy="50"r="40"fill="blue"/>
</svg>
If your SVG files are exported from tools like Illustrator, Inkscape, or Figma, they often include the version attribute by default. You can safely strip it out manually or use an SVG optimizer like SVGO to clean up unnecessary attributes automatically.
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