Skip to main content
HTML Validation

Bad value X for attribute “srcset” on element “source”: Bad image-candidate URL: X: Percentage ("%") is not followed by two hexadecimal digits.

About This HTML Issue

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., %2 instead 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

  1. Find the offending % character in your srcset URL.
  2. If the % is meant literally (e.g., as part of a percentage value like 80%), encode it as %25.
  3. If the % is part of an incomplete percent-encoding (e.g., %2 instead of %2F), correct it to the full three-character sequence.
  4. 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">
  <img src="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">
  <img src="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">
  <img src="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">
  <img src="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"
    type="image/webp">
  <img src="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&amp;q=75%25 480w,
            https://example.com/img.webp?w=800&amp;q=75%25 800w"
    type="image/webp">
  <img src="https://example.com/img.jpg" alt="Blog header image">
</picture>

Note that in the corrected example, & is also encoded as &amp; within the HTML attribute, which is required for valid markup when using ampersands in attribute values.

Find issues like this automatically

Rocket Validator scans thousands of pages in seconds, detecting HTML issues across your entire site.

Help us improve our guides

Was this guide helpful?

Ready to validate your sites?
Start your free trial today.