tiangolo/fastapi · error · RuntimeError

Could not find release notes section for {version} in {relea

Error message

Could not find release notes section for {version} in {release_notes_file}

What it means

Raised by get_release_notes_body() in scripts/prepare_release.py:88 when searching for the '## X.Y.Z' heading for the requested version yields no match (version_heading.search returns None at scripts/prepare_release.py:86). This command is meant to print the body of an existing release section; if the section was never created it cannot proceed.

Source

Thrown at scripts/prepare_release.py:88

        raise RuntimeError(f"Release notes already contain a section for {version}")

    latest_header = f"{RELEASE_NOTES_HEADER}{LATEST_CHANGES_HEADER}\n"
    if not content.startswith(latest_header):
        raise RuntimeError(f"{release_notes_file} must start with {latest_header!r}")

    release_header = f"## {version} ({release_date.isoformat()})"
    return content.replace(
        latest_header,
        f"{RELEASE_NOTES_HEADER}{LATEST_CHANGES_HEADER}\n\n{release_header}\n",
        1,
    )


def get_release_notes_body(content: str, version: str, release_notes_file: Path) -> str:
    version_heading = re.compile(rf"(?m)^## {re.escape(version)}(?: \([^)]+\))?$")
    match = version_heading.search(content)
    if not match:
        raise RuntimeError(
            f"Could not find release notes section for {version} in {release_notes_file}"
        )

    next_match = VERSION_HEADING_PATTERN.search(content, match.end())
    end = next_match.start() if next_match else len(content)
    body = content[match.end() : end].strip()
    if not body:
        raise RuntimeError(
            f"Release notes section for {version} in {release_notes_file} is empty"
        )
    return f"{body}\n"


@app.command()
def prepare(
    bump: Annotated[
        BumpType,
        typer.Argument(

View on GitHub (pinned to 3e8d1526d8)

Solutions

  1. Run `prepare <bump>` first so the section for the new version is created.
  2. Manually add a '## <version> (YYYY-MM-DD)' heading to the release notes file if you bumped the version another way.
  3. Confirm the heading matches the pattern '## X.Y.Z' or '## X.Y.Z (date)'.

Example fix

<!-- before: version 1.2.3 in file but no section -->
## Latest Changes

<!-- after -->
## Latest Changes

## 1.2.3 (2026-01-01)
- Initial release
Defensive patterns

Strategy: validation

Validate before calling

import re
from pathlib import Path

def section_present(path: Path, version: str) -> bool:
    pat = re.compile(rf"(?m)^## {re.escape(version)}(?: \([^)]+\))?$")
    return pat.search(path.read_text(encoding="utf-8")) is not None

Try / catch

try:
    body = get_release_notes_body(content, version, release_notes_file)
except RuntimeError as e:
    if "Could not find release notes section" in str(e):
        raise SystemExit(f"Run prepare first to create the {version} section") from e
    raise

Prevention

When it happens

Trigger: Running `python scripts/prepare_release.py release-notes` (which calls get_release_notes_body with the current __version__) when no matching '## <current_version>' heading exists in the release notes file. Happens right after bumping __version__ but before adding the section via prepare.

Common situations: The version file was bumped manually without running prepare, then release-notes is called. The heading uses a different format than VERSION_HEADING_PATTERN expects. The release notes file points at the wrong path.

Related errors


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