Skip to content

linkcheck: strip query/fragment before local-file existence check - #14552

Open
Gooh456 wants to merge 2 commits into
sphinx-doc:masterfrom
Gooh456:fix-linkcheck-local-file-query-fragment
Open

linkcheck: strip query/fragment before local-file existence check#14552
Gooh456 wants to merge 2 commits into
sphinx-doc:masterfrom
Gooh456:fix-linkcheck-local-file-query-fragment

Conversation

@Gooh456

@Gooh456 Gooh456 commented Jul 24, 2026

Copy link
Copy Markdown

Found this in #14542. linkcheck's local-file check passes the raw URI straight to .exists(), so a link like target.html?view=full gets checked against a file literally named target.html?view=full. That file never exists, so it's reported broken even when target.html is right there.

Fix is in sphinx/builders/linkcheck.py, _check(): strip everything from the first # or ? onward before the filesystem check. If nothing's left after stripping (a bare ?query or the link is otherwise empty), treat it as pointing at the current document, same as the existing bare-#fragment handling a few lines above.

Added a small testroot (tests/roots/test-linkcheck-local-file) with a target file referenced via query string, fragment, and query-only, plus a test that asserts all three come back working. Confirmed it fails (all three broken) on the old code and passes with the fix. Full test_build_linkcheck.py suite still passes (49/49).

Didn't touch the uppercase-scheme issue mentioned in the same regression report (#14541) — different code path, leaving that for a separate PR.

Fixes #14542


AI disclosure: yes, I used Claude Code (Anthropic) on this. I had it dig into the regression report, locate the bug in _check(), write the fix, and write the testroot + test case. I reviewed the diff, ran the full linkcheck test suite locally myself, and checked the 3 unrelated CI failures against master before writing the comment about them. So: code and test are AI-generated, drafting/review/verification is me.

Local links like target.html?view=full or target.html#section were
checked against the filesystem using the raw URI, so the query string
or fragment was treated as part of the filename and the check always
failed even when the target file exists.

Strip any #fragment and ?query suffix before the exists() check.  A
link that is only a query/fragment (e.g. ?mode=full) now resolves to
the current document, matching how bare #fragment links are already
handled a few lines above.

Fixes sphinx-doc#14542

Signed-off-by: Kyue <164024549+Gooh456@users.noreply.github.com>
@Gooh456

Gooh456 commented Jul 24, 2026

Copy link
Copy Markdown
Author

checked the 3 failing checks, none of them are this diff's fault. ty and Docutils HEAD both fail on master right now too (ty's just pre-existing type debt across the codebase, Docutils HEAD is a network failure cloning the docutils git mirror, never even gets to running anything). LaTeX's two test failures are in test_epub_anchor_id and test_intl's figure caption test, completely unrelated subsystems to a linkcheck query-string fix. 2415 other tests in that job passed.

@jdillard

Copy link
Copy Markdown
Member

Closing until the PR description is updated in accordance with the AI policy, which is intended to ensure appropriate human oversight: https://www.sphinx-doc.org/en/master/internals/ai-policy.html

@jdillard jdillard closed this Jul 24, 2026
@Gooh456

Gooh456 commented Jul 24, 2026

Copy link
Copy Markdown
Author

added the disclosure to the description. can't reopen it myself (not a maintainer), mind reopening when you get a chance?

@jdillard jdillard reopened this Jul 24, 2026
Comment thread tests/test_builders/test_build_linkcheck.py
…ring

Per jdillard's review: confirms stripping the query doesn't bypass
the underlying file-existence check.
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.

linkcheck reports existing local files as broken when URI contains query or fragment

2 participants