can1357/oh-my-pi · error
No JSON payload found in response
Error message
No JSON payload found in response
What it means
parseJsonPayload extracts a JSON object from raw model text. It accepts a pure JSON object, or finds the first {...} block via regex; if no {...} substring exists at all it throws. This guards the commit analysis pipeline against responses containing no JSON object.
Source
Thrown at packages/coding-agent/src/commit/utils.ts:23
return message.content.find(content => content.type === "toolCall" && content.name === name) as ToolCall | undefined;
}
export function extractTextContent(message: AssistantMessage): string {
return message.content
.filter(content => content.type === "text")
.map(content => content.text)
.join("")
.trim();
}
export function parseJsonPayload(text: string): unknown {
const trimmed = text.trim();
if (trimmed.startsWith("{") && trimmed.endsWith("}")) {
return JSON.parse(trimmed) as unknown;
}
const match = trimmed.match(/\{[\s\S]*\}/);
if (!match) {
throw new Error("No JSON payload found in response");
}
return JSON.parse(match[0]) as unknown;
}
export function normalizeAnalysis(parsed: {
type: ConventionalAnalysis["type"];
scope: string | null;
details: Array<{ text: string; changelog_category?: ChangelogCategory; user_visible?: boolean }>;
issue_refs: string[];
}): ConventionalAnalysis {
return {
type: parsed.type,
scope: parsed.scope?.trim() || null,
details: parsed.details.map(detail => ({
text: detail.text.trim(),
changelogCategory: detail.user_visible ? detail.changelog_category : undefined,
userVisible: detail.user_visible ?? false,
})),View on GitHub (pinned to 9690622007)
Solutions
- Retry generation with a stronger model or higher instruction adherence.
- Inspect the raw response logged upstream to confirm the model ignored the JSON format and fix the prompt.
- Ask the model to output only JSON (no prose, no code fences) or strip fences before parsing.
- Handle the throw upstream and fall back to a manual/default commit flow.
Example fix
// before: model replied 'I cannot analyze this diff.' parseJsonPayload(response) // throws // after: prompt ends with 'Respond with a single JSON object and nothing else.'
Defensive patterns
Strategy: validation
Validate before calling
function hasJsonPayload(text: string): boolean {
const t = text.trim();
if (t.startsWith("{") && t.endsWith("}")) return true;
return /\{[\s\S]*\}/.test(t);
} Type guard
function isJsonObject(value: unknown): value is Record<string, unknown> {
return typeof value === "object" && value !== null && !Array.isArray(value);
} Try / catch
try {
const analysis = parseJsonPayload(rawResponse);
} catch (err) {
if (err instanceof Error && err.message === "No JSON payload found in response") {
// log rawResponse, retry generation or fall back to default flow
} else throw err;
} Prevention
- End prompts with an explicit 'respond with a single JSON object and nothing else' instruction.
- Strip markdown code fences from model output before parsing.
- Log raw model responses so non-JSON answers are diagnosable.
- Prefer models with structured-output/JSON mode for analysis steps.
When it happens
Trigger: Calling parseJsonPayload (via parsed() or runEvalCompletion) with model output that contains no brace-delimited object — e.g. plain prose, a refusal message, an empty string, or the model describing results without emitting JSON.
Common situations: Model refused the task or answered conversationally instead of following the JSON format instruction; response truncated before any '{'; prompt template drifted so the JSON instruction was lost; tiny local model ignoring the schema.
Related errors
- Model output is not a JSON object
- Replacement text is not valid UTF-8: {err}
- V2 compaction stream parse failed: ${err instanceof Error ?
- OMP_AUTH_BROKER_ACCOUNT_POOL_FILE contains an empty provider
- OMP_AUTH_BROKER_ACCOUNT_POOL_FILE contains a provider id wit
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/6d3d4b03f516d9b1.
Report an issue: GitHub.