Skip to content

Finding broken anchor links in documentation

A link to /docs/auth#refresh-tokens returns 200 whether or not refresh-tokens exists on the page. The reader lands at the top of a long page and scrolls; nobody files a bug; no server log shows an error. That is why anchor links rot faster than any other kind of link in documentation, and why most link checkers never report them.

Why anchors break

  • Heading ids come from heading text. Docusaurus, MkDocs, GitBook, Mintlify, Starlight and most other platforms slugify the heading to make its id. Edit "Refresh tokens" to "Refreshing tokens" and the id changes from refresh-tokens to refreshing-tokens.
  • Duplicate headings get suffixes. Two "Example" headings become example and example-1; insert a third above them and every suffix shifts.
  • Case and encoding differ across platforms. One generator lowercases, another keeps case; one encodes spaces as -, another as _. A link copied from the old platform points at an anchor that no longer matches after a migration.
  • Client-rendered pages have no anchors in the HTML. If headings are built by JavaScript, a plain HTTP check sees an empty shell and either misses the problem or reports every anchor as missing.

How to find them

  1. Start with one page. The broken anchor checker takes a page URL, collects every #fragment link on it (same-page and cross-page), fetches up to 50 target pages, rendering them in a browser when needed, and compares each fragment with the element ids on the target. Matches are case-sensitive; near misses are reported with a hint (case-only or slug-format differences) and the closest existing anchors.
  2. Then crawl the site. The docs link checker runs the same anchor check across a 50-page sample along with every other rule. PathIntact does it for the whole site on a schedule.
  3. Check what links to you. Anchors targeted from your product, your changelog and external sites are the ones nobody inside the docs will notice. Keep a list of the fragments you advertise and test them after every heading change.

How to fix them without breaking more

  • Prefer explicit ids over renaming links. Where the platform supports it (## Heading {#stable-id} in Docusaurus and several MDX-based tools; TODO(verify) per platform), give important headings an explicit id that does not change with the wording.
  • Fix the link, not the heading, when the heading changed for a reason. The checker's closest-match suggestion usually is the new id.
  • Add a redirect anchor when many external links point at the old id. An empty element with the old id placed above the heading keeps external deep links working.
  • Do not let duplicate headings exist. Suffixed ids are unstable by construction.

Keep them from breaking again

Anchor problems are confirmed on a second check before PathIntact alerts, so a heading edited and reverted in the same afternoon does not page anyone. Each alert names the source page, the target page, the missing fragment and the closest existing anchors, so the fix is a one-line change.

Last updated 2026-09-16.