{"record":{"id":"5bf0d8a4b1e66e24","repo":"tiangolo/fastapi","slug":"release-notes-file-must-start-with-latest-heade","errorCode":null,"errorMessage":"{release_notes_file} must start with {latest_header!r}","messagePattern":"(.+?) must start with (.+?)","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"scripts/prepare_release.py","lineNumber":74,"sourceCode":"        raise RuntimeError(\n            f\"New version {version} must be greater than current version {current_version}\"\n        )\n    return VERSION_PATTERN.sub(f'__version__ = \"{version}\"', content, count=1)\n\n\ndef update_release_notes(\n    content: str, version: str, release_date: date, release_notes_file: Path\n) -> str:\n    if not content.startswith(RELEASE_NOTES_HEADER):\n        raise RuntimeError(\n            f\"{release_notes_file} must start with {RELEASE_NOTES_HEADER!r}\"\n        )\n    if re.search(rf\"^## {re.escape(version)}(?: \\([^)]+\\))?$\", content, re.M):\n        raise RuntimeError(f\"Release notes already contain a section for {version}\")\n\n    latest_header = f\"{RELEASE_NOTES_HEADER}{LATEST_CHANGES_HEADER}\\n\"\n    if not content.startswith(latest_header):\n        raise RuntimeError(f\"{release_notes_file} must start with {latest_header!r}\")\n\n    release_header = f\"## {version} ({release_date.isoformat()})\"\n    return content.replace(\n        latest_header,\n        f\"{RELEASE_NOTES_HEADER}{LATEST_CHANGES_HEADER}\\n\\n{release_header}\\n\",\n        1,\n    )\n\n\ndef get_release_notes_body(content: str, version: str, release_notes_file: Path) -> str:\n    version_heading = re.compile(rf\"(?m)^## {re.escape(version)}(?: \\([^)]+\\))?$\")\n    match = version_heading.search(content)\n    if not match:\n        raise RuntimeError(\n            f\"Could not find release notes section for {version} in {release_notes_file}\"\n        )\n\n    next_match = VERSION_HEADING_PATTERN.search(content, match.end())","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/tiangolo/fastapi/blob/3e8d1526d83a90aaf7d6eb6dc682bf150f180b25/scripts/prepare_release.py#L56-L92","documentation":"Raised by update_release_notes() in scripts/prepare_release.py:74. After confirming the release-notes header (error 113) and absence of the target version (error 114), the function requires the '## Latest Changes' heading to immediately follow the header (latest_header at scripts/prepare_release.py:72). New version sections are spliced in right after '## Latest Changes', so its presence and position are mandatory.","triggerScenarios":"Calling prepare when the release-notes file is missing the '## Latest Changes' heading, or it has been moved below existing version sections, or its text was altered.","commonSituations":"A previous release moved '## Latest Changes' but did not restore it. Someone renamed the heading. The file was hand-edited to put a version section above '## Latest Changes'.","solutions":["Open the release notes file and ensure '## Latest Changes' appears immediately after the '# Release Notes' header.","If prior version sections sit above it, move '## Latest Changes' back to the top (just under the H1).","Re-run prepare."],"exampleFix":"<!-- before -->\n# Release Notes\n\n## 1.0.0 (2026-01-01)\n- ...\n\n## Latest Changes\n<!-- after -->\n# Release Notes\n\n## Latest Changes\n\n## 1.0.0 (2026-01-01)\n- ...","handlingStrategy":"validation","validationCode":"from pathlib import Path\n\nRELEASE_NOTES_HEADER = \"---\\nhide:\\n  - navigation\\n---\\n\\n# Release Notes\\n\\n\"\nLATEST_CHANGES_HEADER = \"## Latest Changes\"\n\ndef latest_header_ok(path: Path) -> bool:\n    return path.read_text(encoding=\"utf-8\").startswith(\n        RELEASE_NOTES_HEADER + LATEST_CHANGES_HEADER + \"\\n\"\n    )","typeGuard":null,"tryCatchPattern":"try:\n    updated = update_release_notes(content, version, d, release_notes_file)\nexcept RuntimeError as e:\n    if \"Latest Changes\" in str(e):\n        raise SystemExit(f\"Restore '## Latest Changes' under the header: {e}\") from e\n    raise","preventionTips":["Always keep '## Latest Changes' directly under the '# Release Notes' header.","After splicing a version section, ensure '## Latest Changes' remains above released sections.","CI: assert the file starts with header + '## Latest Changes\\n'."],"tags":["release","docs","validation","markdown"],"backgroundTag":null,"analyzedSha":"3e8d1526d83a90aaf7d6eb6dc682bf150f180b25","analyzedAt":"2026-08-11T02:34:52.986Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}