sphinx-doc / sphinx-doc/sphinx

linkcheck reports uppercase-scheme URIs as broken

Open Beginner friendly
#14,541 5 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

builder:linkcheck type:bug
Dominant language
Python
Stars
8k
Forks
2.6k
PR merge metrics
No merged PRs in 30d

Description

Describe the bug

Sphinx's linkcheck builder uses a case-sensitive regex (([a-z]+:)?//) to detect non-HTTP URI schemes. URIs with uppercase schemes like FTP:// or HTTP:// are not recognized as external links, causing them to be checked as local file paths and reported as [broken].

Per RFC 3986 §3.1, URI schemes are case-insensitive. The code at line 471-473 of sphinx/builders/linkcheck.py intends to return unchecked for non-HTTP schemes (e.g. FTP), but fails for uppercase variants because the regex only matches lowercase.

How to Reproduce
import io
import shutil
from pathlib import Path
from sphinx.application import Sphinx

root = Path("/tmp/sphinx_linkcheck_test")
shutil.rmtree(root, ignore_errors=True)
(root / "_build").mkdir(parents=True)
(root / "conf.py").write_text("")
(root / "index.rst").write_text(
    "Test\n====\n\n`download <FTP://example.test/file>`_\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 output:

index.rst:4: [unchecked] FTP://example.test/file

Actual output:

index.rst:4: [broken] FTP://example.test/file:
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 path in sphinx/builders/linkcheck.py:

uri_re = re.compile('([a-z]+:)?//')  # line 64 — case-sensitive (https://github.com/sphinx-doc/sphinx/blob/master/sphinx/builders/linkcheck.py#L64)

if not uri.startswith(('http:', 'https:')):
    if uri_re.match(uri): # https://github.com/sphinx-doc/sphinx/blob/master/sphinx/builders/linkcheck.py#L472
        # Non-supported URI schemes (ex. ftp)
        return _Status.UNCHECKED, '', 0    # ← intended for FTP://, but never reached
    # falls through to local file check → reports [broken]

A fix would be making the regex case-insensitive: re.compile('([a-z]+:)?//', re.IGNORECASE) or using [a-zA-Z]+.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in sphinx/builders/linkcheck.py around the URI regex at lines 64 and 471-473, then reproduce the issue with the Sphinx application example in the report. Verify that uppercase-scheme URIs such as FTP://example.test/file are treated as external and produce [unchecked] rather than [broken], while existing HTTP and HTTPS handling remains unchanged.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
documentation
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
78/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.