fastapi/fastapi · error · RuntimeError
{release_notes_file} must start with {RELEASE_NOTES_HEADER!r
Error message
{release_notes_file} must start with {RELEASE_NOTES_HEADER!r} What it means
Format check in scripts/prepare_release.py update_release_notes (:60-67): the release-notes markdown file must begin with the exact two headers '# Release Notes' followed immediately by '## Latest Changes' (RELEASE_NOTES_HEADER + LATEST_CHANGES_HEADER + newline). The first check (:61-63) fails if the file does not start with '# Release Notes' at all; the new release section is spliced right after '## Latest Changes', so a reordered/missing header breaks the splice and the script refuses to edit the file.
Source
Thrown at scripts/prepare_release.py:66
if bump == "minor":
return f"{major}.{minor + 1}.0"
return f"{major}.{minor}.{patch + 1}"
def update_version_file(content: str, version: str, version_file: Path) -> str:
current_version = get_current_version(content, version_file)
if parse_version(version) <= parse_version(current_version):
raise RuntimeError(
f"New version {version} must be greater than current version {current_version}"
)
return VERSION_PATTERN.sub(f'__version__ = "{version}"', content, count=1)
def update_release_notes(
content: str, version: str, release_date: date, release_notes_file: Path
) -> str:
if not content.startswith(RELEASE_NOTES_HEADER):
raise RuntimeError(
f"{release_notes_file} must start with {RELEASE_NOTES_HEADER!r}"
)
if re.search(rf"^## {re.escape(version)}(?: \([^)]+\))?$", content, re.M):
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:View on GitHub (pinned to a1fa70d423)
Solutions
- Make docs/en/docs/release-notes.md start with exactly '# Release Notes\n\n## Latest Changes\n' (then the existing changelog body).
- Remove any content above '# Release Notes' (move badges/notes into the body).
- Restore via git: git checkout HEAD -- docs/en/docs/release-notes.md if the edit was accidental (after saving any wanted entries).
- Re-run the release command once the header block matches.
Example fix
# docs/en/docs/release-notes.md (before) <!-- banner --> # Release Notes ## Latest Changes # after # Release Notes ## Latest Changes
Defensive patterns
Strategy: validation
Validate before calling
EXPECTED_HEAD = "# Release Notes\n\n## Latest Changes\n"
def release_notes_wellformed(text: str) -> bool:
return text.startswith("# Release Notes") and text.startswith(EXPECTED_HEAD) Prevention
- Never add content above '# Release Notes' in release-notes.md; new entries go under '## Latest Changes'.
- Protect the file's header block with a CI lint that asserts the startswith(EXPECTED_HEAD) invariant.
- Restore accidentally edited headers from git before re-running release prep.
When it happens
Trigger: Running release preparation when docs/en/docs/release-notes.md was edited to remove or reorder the leading headers, when a stray line (badge, blank intro, HTML comment) was added above '# Release Notes', or when the wrong file was passed as release_notes_file.
Common situations: Contributors prepending banners or acknowledgements to the top of release-notes.md; tools that regenerate the file without the header; checking out a branch where the header was refactored.
Related errors
- Invalid version: {version!r}. Expected format: X.Y.Z
- Expected exactly one __version__ assignment in {version_file
- New version {version} must be greater than current version {
- Couldn't auto-generate sponsors section
- Couldn't find pre section (<style>) in index.md
AI-assisted analysis of fastapi/fastapi@a1fa70d423 (2026-08-14).
Data as JSON: /api/errors/45159a16068fb438.
Report an issue: GitHub.