tiangolo/fastapi · error · ValueError

Number of markdown links does not match the number in the or

Error message

Number of markdown links does not match the number in the original document ({len(links)} vs {len(original_links)})

What it means

Raised by `replace_markdown_links` (scripts/doc_parsing_utils.py:323) as a ValueError when the number of markdown links `[text](url)` found in a translated document differs from the original English document. The translation pipeline rewrites link URLs (e.g. injecting a language code) using positional correspondence, so the link counts must match; a mismatch means a link was added, removed, or escaped differently.

Source

Thrown at scripts/doc_parsing_utils.py:323

        link += f"{{{attributes}}}"

    return link


def replace_markdown_links(
    text: list[str],
    links: list[MarkdownLinkInfo],
    original_links: list[MarkdownLinkInfo],
    lang_code: str,
) -> list[str]:
    """
    Replace markdown links in the given text with the original links.

    Fail if the number of links does not match the original.
    """

    if len(links) != len(original_links):
        raise ValueError(
            "Number of markdown links does not match the number in the "
            "original document "
            f"({len(links)} vs {len(original_links)})"
        )

    modified_text = text.copy()
    for i, link_info in enumerate(links):
        link_text = link_info["text"]
        link_title = link_info["title"]
        original_link_info = original_links[i]

        # Replace
        replacement_link = _construct_markdown_link(
            url=original_link_info["url"],
            text=link_text,
            title=link_title,
            attributes=original_link_info["attributes"],
            lang_code=lang_code,

View on GitHub (pinned to 3e8d1526d8)

Solutions

  1. Restore the same number of markdown links as the English source, in the same order.
  2. Keep `![images](url)` distinct from text links; do not convert one into the other.
  3. Re-sync the translation from the latest English doc to recover link structure.

Example fix

// before (translation has 1 link, English has 2)
See [docs](/docs).
// after
See [docs](/docs) and [tutorial](/tutorial).
Defensive patterns

Strategy: validation

Validate before calling

from scripts.doc_parsing_utils import extract_markdown_links

def markdown_link_counts_match(translated_lines, en_lines) -> bool:
    return len(extract_markdown_links(translated_lines)) == len(extract_markdown_links(en_lines))

Type guard

def same_markdown_link_count(translated_lines, en_lines) -> bool:
    from scripts.doc_parsing_utils import extract_markdown_links
    return len(extract_markdown_links(translated_lines)) == len(extract_markdown_links(en_lines))

Prevention

When it happens

Trigger: Running the docs translation check on a file where a translator removed a link, converted `[text](url)` to plain text, or added a new link. An image `![alt](url)` was turned into a link, or a link escaped as `\[...\]` incorrectly.

Common situations: Translators dropping links they deemed irrelevant. Splitting/merging paragraphs that changed link count. Escape-character differences (`\[` vs `[`). Links wrapped differently across line breaks.

Related errors


AI-assisted analysis of tiangolo/fastapi@3e8d1526d8 (2026-08-11). Data as JSON: /api/errors/0ce885132c37cc9d. Report an issue: GitHub.