tiangolo/fastapi · error · ValueError
Header levels do not match between document and original doc
Error message
Header levels do not match between document and original document (found {header_info['hashes']}, expected {original_header_info['hashes']}) for header №{header_no + 1} in line {header_info['line_no']} What it means
Raised by `replace_header_permalinks` (scripts/doc_parsing_utils.py:234) as a ValueError when the count of permalinks matches but the heading LEVEL (number of '#') for a given header differs between the translated and original document. For example the original has `### Setup` but the translation has `## Setup`. The error names the found/expected hashes, the 1-based header index, and the line number.
Source
Thrown at scripts/doc_parsing_utils.py:234
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"]
permalink = original_header_info["permalink"]
modified_text[line_no] = f"{hashes} {title}{permalink}"
return modified_text
# Markdown links
# --------------------------------------------------------------------------------------
def extract_markdown_links(lines: list[str]) -> list[MarkdownLinkInfo]:View on GitHub (pinned to 3e8d1526d8)
Solutions
- Set the heading level to match the English original: use the same number of '#' for the corresponding header.
- Open both files side by side and align hashes header-by-header at the reported line number.
- Re-run the check after fixing; the error reports the next mismatch if more exist.
Example fix
// before (translation line 42)
## Setup {#setup}
// after (match English ###)
### Setup {#setup} Defensive patterns
Strategy: validation
Validate before calling
from scripts.doc_parsing_utils import extract_header_permalinks
def header_levels_match(translated_lines, en_lines) -> bool:
a = extract_header_permalinks(translated_lines)
b = extract_header_permalinks(en_lines)
return len(a) == len(b) and all(x['hashes'] == y['hashes'] for x, y in zip(a, b)) Type guard
def corresponding_headers_same_level(translated_lines, en_lines) -> bool:
from scripts.doc_parsing_utils import extract_header_permalinks
a = extract_header_permalinks(translated_lines)
b = extract_header_permalinks(en_lines)
return len(a) == len(b) and all(x['hashes'] == y['hashes'] for x, y in zip(a, b)) Prevention
- Mirror the exact '#' count of each heading from the English source.
- Compare files side by side when the check reports a level mismatch.
- Avoid promoting/demoting headings during translation.
When it happens
Trigger: Running the docs translation check where a translator changed `##` to `###` (or vice versa) for a heading while keeping the same total number of headers. Promoting/demoting a section's level during translation.
Common situations: Translators 'fixing' perceived heading hierarchy. Copy-pasting content that re-leveled headings. Inconsistent heading depth between a sub-section and its translation.
Related errors
- Number of code include placeholders does not match the numbe
- Number of headers with permalinks does not match the number
- 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/70a8c27b4ffd72a4.
Report an issue: GitHub.