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

> Canonical HTML version: https://rocketvalidator.com/html-validation/bad-value-x-for-attribute-href-on-element-a-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/)

Percent-encoding (also called URL encoding) is the mechanism defined by [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986) for representing special or reserved characters in URLs. It works by replacing a character with a `%` sign followed by two hexadecimal digits that correspond to the character's byte value. For example, a space becomes `%20`, an ampersand becomes `%26`, and a literal percent sign becomes `%25`. When a browser or parser encounters `%` in a URL, it expects the next two characters to be valid hexadecimal digits so it can decode them back to the original character.

If the parser finds a `%` that is **not** followed by two hexadecimal digits, it cannot decode the sequence, and the URL is considered invalid. The W3C validator flags this as a bad value for the `href` attribute.

## Common causes

1. **A literal `%` that wasn't encoded.** This is the most frequent cause. For instance, a URL containing a percentage value like `50%` in a query string — the `%` must be written as `%25`.
2. **Truncated percent-encoded sequences.** A sequence like `%2` is incomplete because it only has one hex digit instead of two.
3. **Invalid hex characters after `%`.** A sequence like `%GZ` is invalid because `G` and `Z` are not hexadecimal digits (valid hex digits are `0`–`9` and `A`–`F`).
4. **Copy-pasting URLs from non-web sources.** URLs pasted from documents, emails, or spreadsheets may contain unencoded special characters.

## Why this matters

- **Broken links.** Browsers may interpret the malformed URL differently than intended, leading users to the wrong page or a 404 error.
- **Standards compliance.** The [WHATWG URL Standard](https://url.spec.whatwg.org/) and the HTML specification require that `href` values contain valid URLs. Malformed URLs violate these standards.
- **Accessibility.** Screen readers and assistive technologies rely on well-formed URLs to provide accurate navigation information to users.
- **Interoperability.** While some browsers attempt error recovery on malformed URLs, behavior is not guaranteed to be consistent across all browsers and tools.

## How to fix it

- **Encode literal `%` as `%25`.** If the `%` is meant to appear as part of the URL's content (e.g., in a query parameter value), replace it with `%25`.
- **Complete any truncated sequences.** If you intended a percent-encoded character like `%20`, make sure both hex digits are present.
- **Use proper URL encoding functions.** In JavaScript, use `encodeURIComponent()` for query parameter values. In server-side languages, use the equivalent encoding function (e.g., `urllib.parse.quote()` in Python, `urlencode()` in PHP).

## Examples

### Literal `%` not encoded

```html
<!-- ❌ Bad: the % in "48%" is not followed by two hex digits -->
<a href="https://example.com?width=48%">48% width</a>
```

```html
<!-- ✅ Good: the % is encoded as %25 -->
<a href="https://example.com?width=48%25">48% width</a>
```

### Truncated percent-encoded sequence

```html
<!-- ❌ Bad: %2 is incomplete — it needs two hex digits -->
<a href="https://example.com/path%2file">Download</a>
```

```html
<!-- ✅ Good: %2F is a complete encoding for "/" -->
<a href="https://example.com/path%2Ffile">Download</a>
```

### Invalid hexadecimal characters

```html
<!-- ❌ Bad: %XY contains non-hexadecimal characters -->
<a href="https://example.com/search?q=%XYdata">Search</a>
```

```html
<!-- ✅ Good: if the intent was a literal "%XY", encode the % -->
<a href="https://example.com/search?q=%25XYdata">Search</a>
```

### Multiple unencoded `%` in a URL

```html
<!-- ❌ Bad: both % signs are unencoded -->
<a href="https://example.com?min=10%&max=90%">Range</a>
```

```html
<!-- ✅ Good: both % signs are properly encoded -->
<a href="https://example.com?min=10%25&max=90%25">Range</a>
```
