hreflang and html lang mismatch
"hreflang and html lang mismatch" is three different faults sharing one description, and they have three different fixes. Sorting out which one you have takes about a minute and saves you changing the wrong attribute.
The three mismatches
1. The declaration contradicts the prose. The page says
lang="en" and the text is Spanish. This is the one that does immediate damage: a
screen reader switches pronunciation on that attribute, and a search engine reads it to decide
who the page is for. A translation labelled as the original competes with the original for the
wrong readers instead of reaching its own.
2. The hreflang code contradicts the page's own lang attribute. The page
declares lang="en-GB" while its own hreflang entry calls it de-DE. One
of the two is wrong, and nothing on the page tells you which — you have to read the prose to
find out, which is why this collapses into fault 1 once you look.
3. The hreflang codes are not valid codes. hreflang="en-UK" is
a common one — the country is GB, not UK — as are region codes in the
language slot and vice versa. An invalid code is discarded, silently, and the cluster it was
part of is weakened.
Which one you have, in one minute
Open the page and read three things in this order.
The prose. What language is the body text actually in? Not the navigation — the body. This is the ground truth and everything else is a claim about it.
The <html lang> attribute. Does it match what you just
read? If not, that is fault 1 and it is the one to fix first, because the other two are claims
about a page whose own declaration is wrong.
The page's own hreflang entry. In a correct cluster every page lists every version including itself. Find the line pointing at the URL you are on and check its code against the lang attribute. Disagreement is fault 2.
<html lang="en-gb">
<link rel="alternate" hreflang="en-gb" href="https://example.com/en-gb/shoes" />
<link rel="alternate" hreflang="de-de" href="https://example.com/de-de/schuhe" />
The self-reference and the lang attribute agree there. That is the whole test.
Getting the codes right
The language subtag comes from ISO 639-1 and the optional region from ISO 3166-1 alpha-2, in that order, separated by a hyphen. The traps worth knowing:
- The United Kingdom is
GB.en-UKis not a valid region and is discarded. - Language alone is fine.
enis valid and often better than guessing at a region you do not actually target. - Region alone is not.
hreflang="gb"reads as a language subtag and there is no language "gb". - Some old codes were replaced. Hebrew moved from
iwtohe, Indonesian fromintoid, Yiddish fromjitoyi. The old ones still appear in templates. x-defaultis not a language. It marks the fallback for visitors none of your versions target, and it belongs in the cluster alongside the real entries.
Why the wrong attribute gets changed
Because the hreflang block is the visible, fiddly part, so it gets the attention — while the
single lang attribute sits in the template, was set once years ago, and is copied
onto every page including the translated ones. When a translation is added by duplicating an
existing page, the lang attribute comes along for the ride. Every new language multiplies the
error rather than revealing it.
The reciprocity rule is a separate fault again, and the most common hreflang defect there is: if page A declares B, then B must declare A, or the whole declaration is ignored. That one has its own page — fixing hreflang tags with errors — because it cannot be seen by looking at either page alone.
What Docket checks here, and what it does not
Docket reads the declared language against the language the prose is actually in, and reports the pages where they disagree — fault 1, per page rather than per site, because one translated article among hundreds is the usual shape and it is the page that is wrong rather than the site. It also reports pages with no lang attribute at all, invalid and unrecognised hreflang codes, deprecated language subtags, missing self-references, missing return tags, and hreflang targets that 404, redirect or carry a noindex.
It does not compare a page's hreflang self-reference against its own
lang attribute — fault 2 above. That check does not exist today, and this
page is not going to imply it does. Read the two by hand on a sample of pages, or catch it
through fault 1, which the prose test does find.
The full list is what Docket checks, and the wider procedure is the technical SEO audit. If your pages are built by a framework and the attributes are injected after load, check what the server actually sends first — an attribute that only exists after JavaScript runs is not there for the crawlers that do not run it.
After you change it
Language declarations are template-level, so a fix is usually one edit affecting many pages — which is exactly the shape that wants checking afterwards rather than assuming. Monitoring tells you what changed rather than what is true today, and a crawl of the affected section confirms the new attribute is on every page you expected and none you did not.
Common questions
What is an hreflang and html lang mismatch?
Usually one of three things: the lang attribute contradicts the language the page is written in; the page's own hreflang entry uses a different code from its lang attribute; or the hreflang codes are not valid codes. They have different fixes, so it is worth knowing which one you are looking at.
Which should I fix first, lang or hreflang?
The lang attribute, if it contradicts the prose. Everything else is a claim about a page whose own declaration of itself is wrong, and a screen reader is already mispronouncing the page for real readers today.
Is en-UK valid?
No. The region subtag comes from ISO 3166-1 alpha-2, where the United Kingdom is GB, so en-GB is the valid form. An invalid code is discarded silently, which is why this survives so long in templates.
Do the lang attribute and hreflang have to match exactly?
They have to agree about the language. A page declaring lang="en-gb" whose own hreflang self-reference says de-de is telling two different stories about itself, and one of them is wrong. Reading the body text is what settles which.
Does Docket detect a mismatch between hreflang and the lang attribute?
Not that specific comparison. Docket checks the declared language against the language the prose is actually in, reports missing lang attributes, and validates hreflang codes, self-references, return tags and targets — but it does not compare a page's hreflang self-reference to its own lang attribute.