# Bad value X for attribute “lang” on element “Y”: The language subtag Z is not a valid language subtag.

> Canonical HTML version: https://rocketvalidator.com/html-validation/bad-value-x-for-attribute-lang-on-element-y-the-language-subtag-z-is-not-a-valid-language-subtag
> Attribution: Rocket Validator (https://rocketvalidator.com)
> License: CC BY 4.0 (https://creativecommons.org/licenses/by/4.0/)

The first part of a `lang` value has to be a language code made of letters, like `en` or `fr`, and the validator rejects a wildcard, an underscore, a digit or a template placeholder in that position.

The `lang` attribute takes a BCP 47 language tag: subtags joined by hyphens, starting with the language subtag. That first subtag is almost always a two- or three-letter ISO 639 code like `en`, `pt` or `ast`, optionally followed by a region (`en-GB`), a script (`zh-Hant`) or other registered subtags. When the language subtag contains a character that isn't a letter, the validator reports it with this message. A code that has the right shape but isn't registered, such as `zz`, gets a different error saying it is not a valid ISO language part of a language tag.

A few patterns cause most of these errors. The `*` wildcard means "any language" in the `Accept-Language` HTTP header, but it isn't a language tag, and a template that prints a stored language setting can output it when content is marked as being for all languages. Locale names such as `en_US` or `fr_FR` use an underscore, which HTML doesn't accept as a separator, so the validator reads the whole value as one subtag and shows it in lowercase (`fr_fr`) in the message. Unreplaced placeholders like `%LANG%` or `{lang}` fail the same way.

Replace the value with the tag for the language the content is written in. On a multilingual page, put the main language on `<html>` and give passages in other languages their own `lang`. Screen readers use this value to pick a voice and pronunciation rules, and browsers use it for hyphenation and spell checking. Neither can do that with `*`.

## Invalid example

The document language is a wildcard, and the French paragraph uses a locale name with an underscore:

```html
<!DOCTYPE html>
<html lang="*">
  <head>
    <meta charset="utf-8">
    <title>Opening hours</title>
  </head>
  <body>
    <p>The library opens at 9:00 every weekday.</p>
    <p lang="fr_FR">La bibliothèque ouvre à 9 h en semaine.</p>
  </body>
</html>
```

## Valid example

English on the root element, and a hyphenated tag for the French paragraph:

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Opening hours</title>
  </head>
  <body>
    <p>The library opens at 9:00 every weekday.</p>
    <p lang="fr-FR">La bibliothèque ouvre à 9 h en semaine.</p>
  </body>
</html>
```
