Skip to content

docs(conf): replace blanket anchor-URL ignore with targeted domain exceptions - #556

Merged
k-dimple merged 1 commit into
canonical:mainfrom
aahil-khan:fix/linkcheck-anchor-false-positives
Aug 20, 2026
Merged

docs(conf): replace blanket anchor-URL ignore with targeted domain exceptions#556
k-dimple merged 1 commit into
canonical:mainfrom
aahil-khan:fix/linkcheck-anchor-false-positives

Conversation

@aahil-khan

Copy link
Copy Markdown
Contributor

Summary

linkcheck_ignore contained r'.*#.*', which skipped every URL containing a # — not just the anchor check, but the entire link, including whether the base URL was reachable.

This meant a genuinely dead link could silently pass make linkcheck as long as it contained a fragment.

This replaces the blanket ignore with targeted linkcheck_anchors_ignore_for_url entries (a Sphinx builtin, already used here for github.com) for the specific domains that produce false Anchor not found positives.

URLs are still checked for reachability; only the unreliable in-page anchor match is skipped.

How the Domain List Was Built

I removed the blanket ignore locally and ran make linkcheck via sphinx-build -b linkcheck against every subproject in the repo:

  • aws
  • azure
  • google
  • oracle
  • ibm
  • oci
  • vmware
  • public-images
  • all-clouds

For every link flagged as [broken] ... Anchor 'x' not found, I fetched the same URL and inspected the raw HTML received by the linkcheck builder to distinguish genuine breakage from false positives.

Every false positive fell into one of three categories:

  • Client-side rendered anchorsubuntu.com, docs.aws.amazon.com, developer.hashicorp.com, docs.oracle.com, and azure.microsoft.com inject heading IDs via JavaScript after page load. The static HTML fetched by Sphinx's linkcheck does not contain the target ID, even though the link works correctly for a real reader.

    • HashiCorp provided a useful confirmation: its rendered ID is user-content-<slug>, while the public URL fragment omits the user-content- prefix. Client-side JavaScript bridges the gap, but a static fetch cannot.
  • Client-side hash routing, not anchors at allportal.azure.com / portal.azure.cn (#create/...) and console.aws.amazon.com (#/case/...) use # for SPA routing. There is no server-rendered element for Sphinx to find.

  • Flaky parsingcloud.ibm.com: the anchor genuinely exists in the HTML, verified with plain curl, but I reproduced the failure twice using Sphinx's own AnchorCheckParser directly against the live response. Python's html.parser intermittently fails to find the anchor. This is worth raising with Sphinx upstream separately and is out of scope for this PR.

No genuinely broken link was found or newly masked by this change.

Verification

Ran make linkcheck per subproject after the change:

  • aws, azure, google, oracle, ibm — zero Anchor not found results remain.
  • Remaining [broken] results across the repo are unrelated pre-existing issues (for example, askubuntu.com and a couple of Red Hat documentation URLs returning 403 to automated requests). These are not anchor-related and are not touched by this PR.

'linkcheck_ignore' contained r'.*#.*', which skipped every URL with a
'#' entirely -- including the base URL reachability check, not just
the anchor. That hides genuinely broken links, not just unreliable
anchor checks.

Replace it with targeted 'linkcheck_anchors_ignore_for_url' entries
for the specific domains verified (by running linkcheck against every
subproject and inspecting the raw HTML each flagged link received) to
produce false "Anchor not found" positives -- sites that render their
heading ids/anchors client-side with JavaScript, use client-side hash
routing instead of real anchors, or serve markup that reproducibly
defeats Python's HTML parser. This still checks that every URL is
reachable; it only skips the unreliable in-page anchor match for
these known-bad domains.

Verified across the aws, azure, google, oracle, and ibm subprojects:
zero anchor false positives remain, and no genuine link breakage was
uncovered or masked by the change.
@aahil-khan

Copy link
Copy Markdown
Contributor Author

Three RTD checks are failing here (canonical-azure, canonical-gcp, canonical-oracle).

I don't think this is caused by this PR's diff: the only change is to linkcheck_ignore / linkcheck_anchors_ignore_for_url in docs/conf.py, which are only used by the linkcheck builder. This repo's RTD config uses builder: dirhtml, so these settings shouldn't affect the RTD build.

I also reproduced the dirhtml build locally for azure with -W --keep-going and it completed cleanly with zero warnings.

The base commit (6d37791, tip of main) had all 9 RTD checks green when #555 merged four days ago, so I don't think this is a stale cross-project reference issue either.

@k-dimple, do you have any idea what might be causing these three RTD checks to fail?

@k-dimple

Copy link
Copy Markdown
Collaborator

@aahil-khan thanks for the PR! The three RTD failures were some transient 502 errors. They were resolved with a rebuild. The changes look good, I tried them out locally as well. I'll go ahead and merge this. Thanks for the thorough analysis and update!

@k-dimple
k-dimple merged commit 040cdf9 into canonical:main Aug 20, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants