Describe the bug
Linkcheck's local-file validation passes the raw URI (including query and fragment components) directly to a filesystem existence check. As a result, existing local files referenced with ?query or #fragment are incorrectly reported as broken.
For example, target.html exists, but the link target.html?view=full is checked as the literal filename target.html?view=full instead of stripping the query first.
How to Reproduce
import io
import shutil
from pathlib import Path
from sphinx.application import Sphinx
root = Path("/tmp/sphinx_linkcheck_test3")
shutil.rmtree(root, ignore_errors=True)
(root / "_build").mkdir(parents=True)
(root / "target.html").write_text("Target", encoding="utf-8")
(root / "conf.py").write_text("")
(root / "index.rst").write_text(
"Test\n====\n\n`target <target.html?view=full>`_\n"
)
app = Sphinx(str(root), str(root), str(root / "_build"), str(root / "_doctree"),
"linkcheck", status=io.StringIO(), warning=io.StringIO())
app.build(force_all=True)
print((root / "_build" / "output.txt").read_text())
Expected: index.rst:4: [working] target.html?view=full
Actual: index.rst:4: [broken] target.html?view=full:
The same issue occurs with fragments (target.html#section) and query-only URIs (?mode=full).
Environment Information
Sphinx: 9.0.4
Python: 3.11.13
Platform: Linux
Sphinx extensions
Additional context
This regression was introduced by PR #7985.
The relevant code at sphinx/builders/linkcheck.py line 475:
if (hyperlink.docpath.parent / uri).exists():
The uri here is the raw string target.html?view=full — it should first strip ? and # suffixes before checking the filesystem.
Describe the bug
Linkcheck's local-file validation passes the raw URI (including query and fragment components) directly to a filesystem existence check. As a result, existing local files referenced with
?queryor#fragmentare incorrectly reported as broken.For example,
target.htmlexists, but the linktarget.html?view=fullis checked as the literal filenametarget.html?view=fullinstead of stripping the query first.How to Reproduce
Expected:
index.rst:4: [working] target.html?view=fullActual:
index.rst:4: [broken] target.html?view=full:The same issue occurs with fragments (
target.html#section) and query-only URIs (?mode=full).Environment Information
Sphinx extensions
Additional context
This regression was introduced by PR #7985.
The relevant code at
sphinx/builders/linkcheck.pyline 475:The
urihere is the raw stringtarget.html?view=full— it should first strip?and#suffixes before checking the filesystem.