tiangolo/fastapi · error · RuntimeError
Release notes section for {version} in {release_notes_file}
Error message
Release notes section for {version} in {release_notes_file} is empty What it means
Raised by get_release_notes_body() in scripts/prepare_release.py:96 when the version section heading exists but its body (text up to the next '## ' heading, stripped) is empty (scripts/prepare_release.py:94-95). The release-notes command is meant to output the changelog body for tooling, so an empty body is treated as an error rather than emitting nothing.
Source
Thrown at scripts/prepare_release.py:96
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(
envvar="PREPARE_RELEASE_BUMP",
help="The release bump to make: major, minor, or patch.",
),
],
version_file: Annotated[
Path,
typer.Option(
envvar="PREPARE_RELEASE_VERSION_FILE",View on GitHub (pinned to 3e8d1526d8)
Solutions
- Populate the section with at least one changelog entry under the '## <version>' heading.
- Remove the empty heading if the version is not being released.
- Re-run release-notes once the section has content.
Example fix
<!-- before --> ## 1.2.3 (2026-01-01) ## 1.2.2 (2025-12-01) <!-- after --> ## 1.2.3 (2026-01-01) - Fixed login redirect ## 1.2.2 (2025-12-01)
Defensive patterns
Strategy: validation
Validate before calling
import re
from pathlib import Path
def section_has_body(path: Path, version: str) -> bool:
text = path.read_text(encoding="utf-8")
m = re.search(rf"(?m)^## {re.escape(version)}(?: \([^)]+\))?$", text)
if not m:
return False
nxt = re.search(r"(?m)^## ", text[m.end():])
body = text[m.end(): m.end() + (nxt.start() if nxt else len(text) - m.end())].strip()
return bool(body) Try / catch
try:
body = get_release_notes_body(content, version, release_notes_file)
except RuntimeError as e:
if "is empty" in str(e):
raise SystemExit(f"Add changelog entries under ## {version}") from e
raise Prevention
- Require at least one bullet under each version heading before tagging a release.
- CI: fail if a released version's section body is empty.
- Remove stub headings for versions you do not intend to release.
When it happens
Trigger: Running `release-notes` for a version whose '## X.Y.Z' heading was added but contains no bullet points (e.g. a placeholder section), or where all content between headings is whitespace.
Common situations: prepare created the heading but no PR descriptions were added under it. A maintainer added the heading as a stub. Content was accidentally deleted leaving the heading orphaned.
Related errors
- {release_notes_file} must start with {RELEASE_NOTES_HEADER!r
- {release_notes_file} must start with {latest_header!r}
- Could not find release notes section for {version} in {relea
- Number of code include placeholders does not match the numbe
- Number of headers with permalinks does not match the number
AI-assisted analysis of tiangolo/fastapi@3e8d1526d8 (2026-08-11).
Data as JSON: /api/errors/501988be351de24f.
Report an issue: GitHub.