#14675·sphinx

sphinx.ext.viewcode generates a module page with no source links

Author: DarloktCreated Sep 13, 2026Updated Sep 14, 2026
Labelstype:bugextensions:viewcode

Describe the bug

Hej while investigating options for a parallel build of my project, I noticed that a parallel build did not produce the same output as a non-parallel build. Looking closer, it seems that sphinx.ext.viewcode can generate a module page even though no documented object links to it.

A clean parallel HTML build creates:

_modules/index.html
_modules/pkg/_types.html

The documented object has no [source] link, and the module page has no [docs] backlink. The page only contains the highlighted source of the whole module. When I run the same clean build without parallel workers, neither file is created.

PEP 695 is not required to reproduce the problem. I have seen the same result with other kinds of objects, but this example uses a PEP 695 type alias because that is how I originally found the issue.

How to Reproduce

I was able to reproduced this with the following minimal project. It requires Python 3.12 or newer because it uses the PEP 695 type statement.

One can create the minimalproject with these commands:

bash
mkdir -p viewcode-parallel-repro/docs viewcode-parallel-repro/pkg
cd viewcode-parallel-repro

cat > pkg/__init__.py <<'EOF'
from pkg._types import Mode

__all__ = ['Mode']
EOF

cat > pkg/_types.py <<'EOF'
from typing import Literal

type Mode = Literal['a', 'b']
EOF

cat > docs/conf.py <<'EOF'
import sys
from pathlib import Path

sys.path.insert(0, str(Path(__file__).parents[1]))

project = 'viewcode-parallel-repro'
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode']
EOF

cat > docs/api.rst <<'EOF'
API
===

.. autodata:: pkg.Mode
EOF

cat > docs/index.rst <<'EOF'
Reproduction
============

.. toctree::

   api
   filler-1
   filler-2
   filler-3
   filler-4
   filler-5
EOF

printf 'Filler 1\n========\n' > docs/filler-1.rst
printf 'Filler 2\n========\n' > docs/filler-2.rst
printf 'Filler 3\n========\n' > docs/filler-3.rst
printf 'Filler 4\n========\n' > docs/filler-4.rst
printf 'Filler 5\n========\n' > docs/filler-5.rst

The five filler documents make the project large enough for Sphinx to use parallel readers.

Then one can run the fresh non-parallel and parallel builds into separate directories:

bash
sphinx-build -E -a -W -j 1 -b html docs build/serial
sphinx-build -E -a -W -j 2 -b html docs build/parallel

Both builds succeed. The grouped source ranges in the parallel log confirmed that worker reading was used:

Then to check the generated module files:

bash
find build/serial -path '*/_modules/*' -type f
find build/parallel -path '*/_modules/*' -type f

The first command returns nothing. The parallel build returns:

build/parallel/_modules/index.html
build/parallel/_modules/pkg/_types.html

Finally, to check for source link, source block, and backlink:

bash
grep -nE 'viewcode-link|\[source\]' \
  build/serial/api.html build/parallel/api.html
grep -nE 'viewcode-block|viewcode-back' \
  build/parallel/_modules/pkg/_types.html

Neither command returns a match.

Environment Information

Platform:              linux (Linux-7.0.0-31-generic-x86_64-with-glibc2.43)
Python version:        3.13.13 (main, Apr  7 2026, 20:49:46) [Clang 22.1.1 ])
Python implementation: CPython
Sphinx version:        9.1.0
Docutils version:      0.22.4
Jinja2 version:        3.1.6
Pygments version:      2.21.0

Sphinx extensions

python
['sphinx.ext.autodoc', 'sphinx.ext.viewcode']

Additional context

This looks similar to #8756, but that issue concerned stale output after an incremental build. This example uses fresh builds with -E -a.

I can also reproduce the problem with objects other than a PEP 695 type alias. PEP 695 is only used here because that is how I originally found the issue.