# Bad value X for attribute “src” on element “img”: Percentage ("%") is not followed by two hexadecimal digits.

> Canonical HTML version: https://rocketvalidator.com/html-validation/bad-value-x-for-attribute-src-on-element-img-percentage-is-not-followed-by-two-hexadecimal-digits
> Attribution: Rocket Validator (https://rocketvalidator.com)
> License: CC BY 4.0 (https://creativecommons.org/licenses/by/4.0/)

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:

1. **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`.
2. **Incomplete or corrupted percent-encoding** — such as `%2` instead of `%20`, or `%GZ` where the characters after `%` aren't valid hexadecimal digits (only `0`–`9` and `A`–`F`/`a`–`f` are 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](https://url.spec.whatwg.org/) and [RFC 3986](https://www.rfc-editor.org/rfc/rfc3986) 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

1. **Find every bare `%` in the URL** that isn't followed by two hexadecimal digits.
2. **If the `%` is meant as a literal percent sign**, replace it with `%25`.
3. **If the `%` is part of a broken encoding sequence** (e.g., `%2` or `%GH`), correct it to the intended two-digit hex code (e.g., `%20` for a space).
4. **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

```html
<!-- ❌ Bad: bare "%" is not followed by two hex digits -->
<img alt="Chart" src="https://example.com/chart.png?scale=50%">

<!-- ✅ Fixed: "%" encoded as "%25" -->
<img alt="Chart" src="https://example.com/chart.png?scale=50%25">
```

### Incomplete percent-encoding sequence

```html
<!-- ❌ Bad: "%2" is incomplete — missing the second hex digit -->
<img alt="Photo" src="https://example.com/my%2photo.jpg">

<!-- ✅ Fixed: use "%20" for a space character -->
<img alt="Photo" src="https://example.com/my%20photo.jpg">
```

### Non-hexadecimal characters after percent sign

```html
<!-- ❌ Bad: "%zz" uses non-hex characters -->
<img alt="Logo" src="https://example.com/logo%zz.png">

<!-- ✅ Fixed: remove the erroneous sequence if it was unintentional -->
<img alt="Logo" src="https://example.com/logo.png">
```

### Multiple encoding issues in one URL

```html
<!-- ❌ Bad: bare "%" in query value and unencoded space -->
<img alt="Report" src="https://example.com/img?label=100%&name=my file.png">

<!-- ✅ Fixed: "%" → "%25", space → "%20" -->
<img alt="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:

```js
const label = "100%";
const name = "my file.png";
const src = `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.
