can1357/oh-my-pi · error · Error
Markdown analysis type(scope): summary heading not found
Error message
Markdown analysis type(scope): summary heading not found
What it means
parseConventionalAnalysisMarkdown expects the model's analysis to start with a 'type(scope): summary' heading line. It tries strict heading parsing, then coerces the first markdown '#' line. If no valid heading exists anywhere in the text, this error is thrown (raised by parseConventionalAnalysisMarkdown, called by generateDirectAnalysis, runMapReduce, analysis, canonical).
Source
Thrown at packages/coding-agent/src/commit/conventional/markdown.ts:143
if (isRecord(payload)) return analysisFromMapping(payload, defaultType);
const lines = cleanMarkdownText(text).split(/\r?\n/);
let heading: { index: number; type: CommitType; scope: string | null; summary: string } | undefined;
let coerced: typeof heading;
for (let index = 0; index < Math.min(5, lines.length); index += 1) {
const line = lines[index] ?? "";
const candidate = stripHeadingMarkers(line);
const parsed = parseHeadingLine(candidate, false);
if (parsed) {
heading = { index, ...parsed };
break;
}
if (!coerced && line.trim().startsWith("#")) {
const fallback = parseHeadingLine(candidate, true);
if (fallback) coerced = { index, ...fallback };
}
}
heading ??= coerced;
if (!heading) throw new Error("Markdown analysis type(scope): summary heading not found");
const detailTexts: string[] = [];
const issueRefs: string[] = [];
for (const line of lines.slice(heading.index + 1)) {
const stripped = line.trim();
if (!stripped) continue;
const lower = stripped.toLowerCase();
if (lower.startsWith("fixes:") || lower.startsWith("closes:") || lower.startsWith("resolves:")) {
const separator = stripped.indexOf(":");
for (const ref of stripped.slice(separator + 1).split(",")) if (ref.trim()) issueRefs.push(ref.trim());
continue;
}
const bullet = stripBullet(stripped);
if (!bullet) continue;
detailTexts.push(ensureSentence(bullet));
issueRefs.push(...(bullet.match(ISSUE_RE) ?? []));
}
return conventionalAnalysis({
type: heading.type,View on GitHub (pinned to 9690622007)
Solutions
- Retry or switch to a model that reliably follows the type(scope): heading format
- Strengthen the reduce prompt's format instructions / add a format example
- Verify the raw text isn't wrapped in tags/fences the parser doesn't strip; strip them before parsing
- Add leniency: coerce the first non-empty line into the heading if it looks like a conventional commit
Example fix
// before const analysis = parseConventionalAnalysisMarkdown(raw); // after: pre-strip wrappers const cleaned = extractTagLenient(raw, "analysis") ?? raw; const analysis = parseConventionalAnalysisMarkdown(cleaned);
Defensive patterns
Strategy: try-catch
Validate before calling
const headingRe = /^#{0,3}\s*\w+(\([^)]*\))?!?:\s.+$/m;
if (!headingRe.test(raw)) throw new Error("Model output missing type(scope): heading"); Try / catch
try {
const analysis = parseConventionalAnalysisMarkdown(raw);
} catch (err) {
if (err instanceof Error && err.message.includes("heading not found")) {
// regenerate or use a lenient fallback parser
}
throw err;
} Prevention
- Include an explicit format example in the reduce prompt
- Strip <analysis>/<summary> tags and code fences before parsing
- Prefer models known to follow structured output formats for analysis
When it happens
Trigger: Calling parseConventionalAnalysisMarkdown on model output that lacks any 'type(scope): subject' line and has no coercible '#' heading — the model replied with prose, JSON, or wrapped the heading in a code fence or label that defeats the parser.
Common situations: Prompt drift after model changes (model ignores the heading format instruction), small/fast models not following the conventional-commit format, output wrapped in <summary> tags that weren't stripped, or non-conventional commit style like plain sentences.
Related errors
- Markdown summary empty after normalization
- Replacement text is not valid UTF-8: {err}
- V2 compaction stream parse failed: ${err instanceof Error ?
- ${source} response is missing credentials.
- auto-thinking: unparseable local classification: ${JSON.stri
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/e67269b398ec2742.
Report an issue: GitHub.