# Coverage Report Links 404 When You Click Through — Fixing the Drill-Down

Canonical: https://commareports.com/fix/coverage-report-links-broken
Published: 2026-09-07

> The coverage index opens but every file link 404s. Why only index.html travelled, what genhtml, JaCoCo, Istanbul and SimpleCov actually emit, and how to keep the drill-down working.

# The coverage summary loads, the file links 404

`htmlcov/index.html` opens, the table of files renders, the percentages
look right — and clicking any filename gives `File not found`.

## Only the index travelled

Every coverage tool emits a **directory**, not a file. The index is a
table of contents; the content is one generated page per source file:

```
htmlcov/                          # coverage.py
├── index.html                    ← the summary table
├── style.css  coverage_html.js   ← shared assets
├── z_a1b2c3_models_py.html       ← one page per source file
├── z_a1b2c3_views_py.html
└── … several hundred more
```

The names differ, the shape does not:

| Tool                 | Directory               | Assets                          |
| -------------------- | ----------------------- | ------------------------------- |
| coverage.py          | `htmlcov/`              | `style.css`, `coverage_html.js` |
| Istanbul / nyc       | `coverage/lcov-report/` | `prettify.js`, `base.css`       |
| JaCoCo               | `target/site/jacoco/`   | `jacoco-resources/`             |
| SimpleCov            | `coverage/`             | `assets/<version>/`             |
| genhtml (lcov)       | `out/`                  | `gcov.css`, `amber.png`         |
| Go (`go tool cover`) | single file             | — (the exception)               |

Attach `index.html` to a ticket, drop it in a chat, copy it out of the
build directory — and you have shipped the table of contents of a book
you left behind.

## The variants of this bug

**Sorting and search stop working too.** Those are `coverage_html.js`
and friends. Missing assets take the interactivity with them, which
looks like a separate bug and is the same one —
[the five causes of a report losing its CSS](/html-report-broken-css).

**It works locally, 404s in CI.** The artifact upload had a `path:` that
matched only the entry file, or the copy step used the file instead of
the directory.

**It works in CI's viewer, breaks after download.** Now you are on
`file://`, where relative paths and any XHR-loaded data both fail. See
[why localhost was the wrong fix](/fix/localhost-link-doesnt-work-for-others).

**Everything 404s except index.** Some tools emit paths with characters
that a static host or bucket key-encodes differently than the browser
requests them. Bucket hosting also needs per-extension content types, or
the pages [download instead of rendering](/fix/s3-html-downloads-instead-of-opening).

## Keep the whole tree

Publish the directory as a unit. `index.html` becomes the report body;
every generated page, stylesheet and script uploads alongside it with
relative references rewritten to the uploaded copies, so the drill-down
resolves over HTTPS for anyone with the link.

From CI, at the end of the job:

```yaml
- name: Publish coverage
  if: always()
  run: |
    coverage html                      # or nyc report --reporter=lcov-report
    # upload the folder — multi-file call in /docs/ci
```

**Limits:** entry HTML 5 MB; assets 25 MB per file, 250 MB and 500 files
per report. A large monorepo's per-file pages can approach the file
count — scope the report to the package under review, which is usually
what the reviewer wanted anyway.

## Why the drill-down is the point

"Coverage dropped 0.4%" starts an argument that nobody can settle in
chat. The per-line view settles it: the reviewer opens the file, sees
the uncovered branch, selects it, and comments **there** —
[comment on HTML](/comment-on-html). Publish the same report id every
run and each build appends a revision, so the trend and the argument
live at one address.

## Try it

Comma is free — unlimited reports, unlimited commenters, unlimited
revision history.

**[Publish a coverage report →](https://commareports.com/)**

### Related

- [Share a coverage report](/share-coverage-report) · [lcov](/share-lcov-report) · [JaCoCo](/share-jacoco-report)
- [Share an HTML folder](/share-html-folder)
- [My HTML report lost its CSS](/html-report-broken-css)
- [Publish from CI](/docs/ci)
