tiangolo/fastapi · error · ValueError
Number of headers with permalinks does not match the number
Error message
Number of headers with permalinks does not match the number in the original document ({len(header_permalinks)} vs {len(original_header_permalinks)}) What it means
Raised by `replace_header_permalinks` (scripts/doc_parsing_utils.py:223) as a ValueError when the number of headers carrying `{#permalink}` anchors in a translated document differs from the original English document. The docs translation pipeline re-applies English permalinks onto translated headers, so the header count must match exactly; a mismatch indicates the translator added/removed/merged a heading.
Source
Thrown at scripts/doc_parsing_utils.py:223
modified_lines.append(line)
return modified_lines
def replace_header_permalinks(
text: list[str],
header_permalinks: list[HeaderPermalinkInfo],
original_header_permalinks: list[HeaderPermalinkInfo],
) -> list[str]:
"""
Replace permalinks in the given text with the permalinks from the original document.
Fail if the number or level of headers does not match the original.
"""
modified_text: list[str] = text.copy()
if len(header_permalinks) != len(original_header_permalinks):
raise ValueError(
"Number of headers with permalinks does not match the number in the "
"original document "
f"({len(header_permalinks)} vs {len(original_header_permalinks)})"
)
for header_no in range(len(header_permalinks)):
header_info = header_permalinks[header_no]
original_header_info = original_header_permalinks[header_no]
if header_info["hashes"] != original_header_info["hashes"]:
raise ValueError(
"Header levels do not match between document and original document"
f" (found {header_info['hashes']}, expected {original_header_info['hashes']})"
f" for header №{header_no + 1} in line {header_info['line_no']}"
)
line_no = header_info["line_no"] - 1
hashes = header_info["hashes"]
title = header_info["title"]View on GitHub (pinned to 3e8d1526d8)
Solutions
- Align the heading structure of the translation to the English source (same count of `#`/`##`/... headers).
- Do not remove `{#permalink}` anchors; the tool manages them automatically.
- Re-sync the translation against the latest English document.
Example fix
// before # Translation has 2 headers, English has 3 ## Intro ## Details // after ## Intro ## Setup ## Details
Defensive patterns
Strategy: validation
Validate before calling
from scripts.doc_parsing_utils import extract_header_permalinks
def header_counts_match(translated_lines, en_lines) -> bool:
return len(extract_header_permalinks(translated_lines)) == len(extract_header_permalinks(en_lines)) Type guard
def same_header_count(translated_lines, en_lines) -> bool:
from scripts.doc_parsing_utils import extract_header_permalinks
return len(extract_header_permalinks(translated_lines)) == len(extract_header_permalinks(en_lines)) Prevention
- Preserve the heading structure (same number of headers) when translating.
- Never strip {#permalink} anchors; the tooling manages them.
- Re-check the translation whenever the English source heading count changes.
When it happens
Trigger: Running the docs translation check on a file where a heading was deleted, added, or had its `{#...}` permalink stripped/added relative to the English source. A heading was converted to bold text or vice versa.
Common situations: Translators restructuring document sections. Merging/splitting headings during translation. Permalinks removed because the translator thought they were decorative. Out-of-date translation after the English doc changed heading count.
Related errors
- Number of code include placeholders does not match the numbe
- Header levels do not match between document and original doc
- Number of markdown links does not match the number in the or
- Number of HTML links does not match the number in the origin
- Code block (lines {start_line}-{end_line_no}) has different
AI-assisted analysis of tiangolo/fastapi@3e8d1526d8 (2026-08-11).
Data as JSON: /api/errors/68e175f89182d2b8.
Report an issue: GitHub.