JuliusBrussee/caveman · error
cave_output_schema_invalid_json
cave_output_schema_invalid_json
Error message
cave_output_schema_invalid_json
What it means
Thrown when the agent definition declares an output schema (definition.output.schema) and the final assistant message's text is not parseable as JSON. The runtime validates structured output before returning it, so callers never receive invalid JSON typed as valid.
Source
Thrown at packages/agent/src/runtime.ts:2119
throw new Error("cave_subagent_spend_evidence_incomplete");
}
// A run stopped before its first call has no assistant message, and that is
// the honest outcome rather than missing evidence: the caller gets an empty
// answer, zero usage, and the reason the runtime declined to spend.
if (!finalMessage && stopReason === undefined) {
throw new Error("cave_incomplete_evidence: Pi emitted no final assistant message");
}
if (finalMessage &&
(finalMessage.stopReason === "error" || finalMessage.stopReason === "aborted")) {
throw new Error(`cave_provider_terminal_${finalMessage.stopReason}`);
}
const text = finalMessage === undefined ? "" : assistantText(finalMessage);
if (definition.output?.schema && finalMessage !== undefined) {
let parsed: unknown;
try {
parsed = JSON.parse(text);
} catch {
throw new Error("cave_output_schema_invalid_json");
}
if (!Value.Check(definition.output.schema, parsed)) {
throw new Error("cave_output_schema_mismatch");
}
}
if (appliedPlan.appliedTransformIDs.length > 0 && !cacheBoundaryKnown) {
cacheBust = true;
markRequestPassThrough(headers, appliedPlan, "cache_boundary_unobserved");
}
for (const child of nestedReceipts) receipt.recordSubagent(child);
// Built once so the result and its receipt cannot disagree about a breach.
const runReceipt = receipt.build({
runId,
agentId: definition.id,
stopReason: stopReason ?? "complete",
meter: budgetMeter,
...(breakers === undefined ? {} : { breakers: breakers.recorded }),
});View on GitHub (pinned to 27d5a3981a)
Solutions
- Strengthen the output instruction — the injected <cave-output> tag says 'Return output matching declared schema'; reinforce in agent instructions that the final message must be JSON only
- Raise definition.output.maxTokens so the JSON is not truncated
- Use a model with reliable structured-output behavior
- Check appliedPlan for transforms routing the output segment and exclude the final answer from compression
Example fix
// before
const agent = defineAgent({
id: "extractor",
output: { schema: ExtractSchema, maxTokens: 128 }, // too small, JSON truncates
});
// after
const agent = defineAgent({
id: "extractor",
instructions: "Reply with a single JSON object and nothing else.",
output: { schema: ExtractSchema, maxTokens: 2048 },
}); Defensive patterns
Strategy: validation
Validate before calling
// Pre-check the model's answer shape in development by running without a schema
// and validating yourself before enabling definition.output.schema:
function isJson(text: string): boolean {
try { JSON.parse(text); return true; } catch { return false; }
} Type guard
function isInvalidOutputJson(e: unknown): e is Error {
return e instanceof Error && e.message === "cave_output_schema_invalid_json";
} Try / catch
try {
return await agent.run(input, opts);
} catch (e) {
if (isInvalidOutputJson(e)) {
// retry with reinforced JSON-only instructions or higher output maxTokens
} else throw e;
} Prevention
- State 'JSON only, no prose' explicitly in agent instructions
- Size output maxTokens generously for the schema's serialized size
- Exclude the final answer segment from compression transforms
When it happens
Trigger: definition.output.schema is set, a finalMessage exists, and assistantText(finalMessage) fails JSON.parse — the model answered in prose or emitted truncated JSON.
Common situations: Output max_tokens too small so JSON is cut off; instructions not demanding JSON-only output; models weak at instruction-following; transforms (e.g. text/toon compression) applied to the output segment distorting it.
Related errors
- cave_eve_terminal_${result.status}
- cave_harness_upstream_version_mismatch
- cave_mastra_max_steps_invalid
- caveman agent: invalid .caveman/provider.json
- caveman build: invalid .caveman/provider.json
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/d19b7f52fecfb3c9.
Report an issue: GitHub.