{"record":{"id":"6444cfa72ebdde4b","repo":"tiangolo/fastapi","slug":"code-block-lines-start-line-end-line-no-has-6444cf","errorCode":null,"errorMessage":"Code block (lines {start_line}-{end_line_no}) has different number of lines than the original block ({len(block_a['content'])} vs {len(block_b['content'])})","messagePattern":"Code block \\(lines (.+?)-(.+?)\\) has different number of lines than the original block \\((.+?) vs (.+?)\\)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"scripts/doc_parsing_utils.py","lineNumber":590,"sourceCode":") -> list[str]:\n    \"\"\"\n    Replace multiline code block `a` with block `b` leaving comments intact.\n\n    Syntax of comments depends on the language of the code block.\n    Raises ValueError if the blocks are not compatible (different languages or different number of lines).\n    \"\"\"\n\n    start_line = block_a[\"start_line_no\"]\n    end_line_no = start_line + len(block_a[\"content\"]) - 1\n\n    if block_a[\"lang\"] != block_b[\"lang\"]:\n        raise ValueError(\n            f\"Code block (lines {start_line}-{end_line_no}) \"\n            \"has different language than the original block \"\n            f\"('{block_a['lang']}' vs '{block_b['lang']}')\"\n        )\n    if len(block_a[\"content\"]) != len(block_b[\"content\"]):\n        raise ValueError(\n            f\"Code block (lines {start_line}-{end_line_no}) \"\n            \"has different number of lines than the original block \"\n            f\"({len(block_a['content'])} vs {len(block_b['content'])})\"\n        )\n\n    block_language = block_a[\"lang\"].lower()\n    if block_language in {\"mermaid\"}:\n        if block_a != block_b:\n            print(\n                f\"Skipping mermaid code block replacement (lines {start_line}-{end_line_no}). \"\n                \"This should be checked manually.\"\n            )\n        return block_a[\"content\"].copy()  # We don't handle mermaid code blocks for now\n\n    code_block: list[str] = []\n    for line_a, line_b in zip(block_a[\"content\"], block_b[\"content\"], strict=False):\n        line_a_comment: str | None = None\n        line_b_comment: str | None = None","sourceCodeStart":572,"sourceCodeEnd":608,"githubUrl":"https://github.com/tiangolo/fastapi/blob/3e8d1526d83a90aaf7d6eb6dc682bf150f180b25/scripts/doc_parsing_utils.py#L572-L608","documentation":"Raised by replace_multiline_code_block() in scripts/doc_parsing_utils.py:590 when synchronizing translated documentation code blocks against the English originals. The function preserves translator comments by line-matching each translated code fence line to the corresponding English line, so it requires the two fenced blocks to have identical line counts. If a translator added, removed, or re-wrapped lines inside a fenced code block, the 1:1 comment preservation algorithm cannot run and the function refuses to silently corrupt the output.","triggerScenarios":"Called from check_translation() (scripts/doc_parsing_utils.py:726) which runs over every translated .md file pairing each translated fenced block (block_a) with the English block (original/b). Triggers when len(translated_block['content']) != len(english_block['content']) for any paired fenced code block. The message reports the line range of the offending block in the translated doc and both line counts.","commonSituations":"A translator hand-edited a Python/bash/YAML snippet and added a line, deleted a line, or split one statement into two. The English source changed (added/removed lines) and the translation was not yet re-synced. A fenced block in the translation was merged with adjacent text or had its fence moved.","solutions":["Open the translated file at the line range printed in the message and add or remove lines so the fenced block matches the English block's line count.","Re-run the docs check; if auto_fix was enabled the script prints 'Fixing multiline code blocks in: <path>' once counts align.","If the English source legitimately changed, copy the new English block into the translation and re-apply only the translated comments line-by-line.","For mermaid blocks the script skips replacement automatically (scripts/doc_parsing_utils.py:597) — if the block is mermaid, verify the lang tag is set so it is skipped."],"exampleFix":"// before (translated file, English has 3 lines)\n```Python\nfrom fastapi import FastAPI\napp = FastAPI()\n```\n// after (add the missing line to match English line count)\n```Python\nfrom fastapi import FastAPI\napp = FastAPI()\n@app.get(\"/\")\n```","handlingStrategy":"validation","validationCode":"from scripts.doc_parsing_utils import extract_multiline_code_blocks\n\ndef assert_blocks_match(en_lines: list[str], translated_lines: list[str]) -> None:\n    en = extract_multiline_code_blocks(en_lines)\n    tr = extract_multiline_code_blocks(translated_lines)\n    assert len(en) == len(tr), f\"block count {len(tr)} != en {len(en)}\"\n    for i, (a, b) in enumerate(zip(tr, en)):\n        assert len(a['content']) == len(b['content']), (\n            f\"block {i} (line {a['start_line_no']}): \"\n            f\"{len(a['content'])} != {len(b['content'])}\"\n        )","typeGuard":null,"tryCatchPattern":"try:\n    fixed = replace_multiline_code_blocks_in_text(doc_lines, doc_blocks, en_blocks)\nexcept ValueError as e:\n    logging.error(f\"Code block mismatch in {path}: {e}\")\n    # surface the file/line range to the translator; do not auto-rewrite","preventionTips":["When translating a fenced block, keep the same number of lines; only edit text within existing lines.","Run check_translation on translated files in CI before merge.","If the English source changed line count, port the structural change into every translation."],"tags":["docs","translation","markdown","validation"],"backgroundTag":null,"analyzedSha":"3e8d1526d83a90aaf7d6eb6dc682bf150f180b25","analyzedAt":"2026-08-11T02:34:52.986Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}