Skip to content

Check the built docs for broken internal links - #2975

Merged
pvcraven merged 1 commit into
developmentfrom
check-internal-links
Oct 9, 2026
Merged

pvcraven merged 1 commit into
developmentfrom
check-internal-links

Conversation

@pvcraven

@pvcraven pvcraven commented Oct 9, 2026

Copy link
Copy Markdown
Member

Closes #1168. Part 2, after #2974 fixed the existing broken links.

uv run make.py docs-full, which CI's docs job runs, now runs util/check_internal_links.py build after the Sphinx build. It fails the build if any page links to a page, file or anchor that doesn't exist.

Why

Since #2970, nitpicky mode catches broken cross-references (:ref:, :py:class: and so on). It doesn't see plain links, which is how these got through:

The script checks the HTML Sphinx actually wrote, so it catches any of these, whatever the source.

How it works

  • It scans every built page except Sphinx's generated _modules/, _static/, _sources/, genindex and search pages.
  • For each href/src, it checks that the target file exists. For #anchor links to an HTML page, it checks that the page has that id.
  • It skips external links (http, https, mailto, data) and cache-busting query strings (?v=...).
  • Every page repeats the sidebar, so it checks each link once per folder. A full build (859 pages) takes about 2 seconds.
  • It uses os.path.normpath, not Path.resolve(). resolve() hung on some links on Windows.
  • It also adds the missing import sys to make.py, which the new line needs.

Per #1168's discussion, this doesn't check external links. Those go down unpredictably, so make.py linkcheck stays a manual command.

Tested

  • uv run make.py docs-full from a clean build/ passes. The Sphinx build plus the check report "No broken internal links".
  • On a build from before Fix broken links in the docs #2974, the script reports the 20 broken links Fix broken links in the docs #2974 fixed and exits 1. run() in make.py exits with a failing command's status, so docs-full fails too.
  • ruff format and lint pass.

🤖 Generated with Claude Code

Sphinx's nitpicky mode catches broken cross-references, but not plain
links such as a figure's :target: or a named link missing its trailing
underscore. util/check_internal_links.py scans the HTML Sphinx wrote
for links to pages, files or anchors that don't exist, and make.py
docs-full, which CI runs, now runs it after the build.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@pvcraven
pvcraven merged commit 275bdc2 into development Oct 9, 2026
7 checks passed
@pvcraven
pvcraven deleted the check-internal-links branch October 9, 2026 20:21
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.

Automate broken link detection for documentation

1 participant