tiangolo/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
Raised by update_release_notes() in scripts/prepare_release.py:66 when the release-notes Markdown file does not start with the exact RELEASE_NOTES_HEADER (front matter hiding navigation, a blank line, '# Release Notes', blank line — scripts/prepare_release.py:12-19). This header is the anchor used to splice in new version sections, so a missing or altered header would misplace new entries.
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 3e8d1526d8)
Solutions
- Open the release notes file and restore the exact header block: '---\nhide:\n - navigation\n---\n\n# Release Notes\n\n'.
- Restore from git history if unsure of the exact bytes.
- Re-run prepare.
Example fix
<!-- before --> # Release Notes <!-- after --> --- hide: - navigation --- # Release Notes
Defensive patterns
Strategy: validation
Validate before calling
from pathlib import Path
RELEASE_NOTES_HEADER = "---\nhide:\n - navigation\n---\n\n# Release Notes\n\n"
def notes_header_ok(path: Path) -> bool:
return path.read_text(encoding="utf-8").startswith(RELEASE_NOTES_HEADER) Try / catch
try:
updated = update_release_notes(content, version, d, release_notes_file)
except RuntimeError as e:
if "must start with" in str(e):
raise SystemExit(f"Release notes header malformed: {e}") from e
raise Prevention
- Treat the release-notes front matter + '# Release Notes' header as immutable scaffolding.
- Add a CI assertion that the file starts with RELEASE_NOTES_HEADER.
- Avoid formatters that rewrite YAML front matter.
When it happens
Trigger: Calling prepare when release_notes_file (docs/en/docs/release-notes.md typically) has had its front-matter block edited, the '# Release Notes' title changed, or trailing whitespace/newlines disturbed the exact prefix match at scripts/prepare_release.py:65.
Common situations: A doc tool reformatted the front matter. The title was translated or renamed. A blank line was removed between front matter and the H1.
Related errors
- {release_notes_file} must start with {latest_header!r}
- Code block (lines {start_line}-{end_line_no}) has different
- Number of code blocks does not match the number in the origi
- Couldn't auto-generate sponsors section
- Couldn't find pre section (<style>) in index.md
AI-assisted analysis of tiangolo/fastapi@3e8d1526d8 (2026-08-11).
Data as JSON: /api/errors/e6205650a0c5aa48.
Report an issue: GitHub.