{"record":{"id":"f29c68d53a609123","repo":"JuliusBrussee/caveman","slug":"cave-incomplete-evidence","errorCode":"cave_incomplete_evidence","errorMessage":"cave_incomplete_evidence: Pi emitted no final assistant message","messagePattern":"cave_incomplete_evidence: Pi emitted no final assistant message","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/agent/src/runtime.ts","lineNumber":2107,"sourceCode":"    }\n    if (ladderFailure) throw ladderFailure;\n    if (spendFailure) throw spendFailure;\n    if (usageFailure !== undefined &&\n        (efficiencyPlan !== undefined ||\n          executionContext.spendLedgers.length > 0 ||\n          usageFailure.message === \"cave_provider_model_identity_mismatch\" ||\n          usageFailure.message === \"cave_provider_identity_missing\")) {\n      throw usageFailure;\n    }\n    if (pendingSpendReservations.length > 0) {\n      markSpendIncomplete(executionContext.spendLedgers);\n      throw new Error(\"cave_subagent_spend_evidence_incomplete\");\n    }\n    // A run stopped before its first call has no assistant message, and that is\n    // the honest outcome rather than missing evidence: the caller gets an empty\n    // answer, zero usage, and the reason the runtime declined to spend.\n    if (!finalMessage && stopReason === undefined) {\n      throw new Error(\"cave_incomplete_evidence: Pi emitted no final assistant message\");\n    }\n    if (finalMessage &&\n        (finalMessage.stopReason === \"error\" || finalMessage.stopReason === \"aborted\")) {\n      throw new Error(`cave_provider_terminal_${finalMessage.stopReason}`);\n    }\n    const text = finalMessage === undefined ? \"\" : assistantText(finalMessage);\n    if (definition.output?.schema && finalMessage !== undefined) {\n      let parsed: unknown;\n      try {\n        parsed = JSON.parse(text);\n      } catch {\n        throw new Error(\"cave_output_schema_invalid_json\");\n      }\n      if (!Value.Check(definition.output.schema, parsed)) {\n        throw new Error(\"cave_output_schema_mismatch\");\n      }\n    }\n    if (appliedPlan.appliedTransformIDs.length > 0 && !cacheBoundaryKnown) {","sourceCodeStart":2089,"sourceCodeEnd":2125,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/packages/agent/src/runtime.ts#L2089-L2125","documentation":"Thrown when the run produced no final assistant message AND no stopReason was recorded — Pi emitted nothing and the runtime did not deliberately stop. Per the inline comment this is 'the honest outcome rather than missing evidence': the caller gets an error instead of a fabricated empty answer.","triggerScenarios":"The provider stream ends without any assistant message and without the budget ladder stopping the run — e.g. the run is interrupted before its first call completes, or the provider closes the stream cleanly but empty.","commonSituations":"Provider returning an empty completion; network interruption before the first token; misconfigured stream that resolves immediately; abort racing the first call.","solutions":["Retry the run — transient empty streams from providers are the most common cause","Log the provider request/response cycle to confirm the provider truly returned no message","Verify your streamFn / provider adapter forwards assistant_message events correctly","If it reproduces deterministically, capture the provider's raw response and file it against the adapter"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":"function isNoFinalMessage(e: unknown): e is Error {\n  return e instanceof Error && e.message.startsWith(\"cave_incomplete_evidence\");\n}","tryCatchPattern":"for (let attempt = 0; attempt < 2; attempt++) {\n  try { return await agent.run(input, opts); }\n  catch (e) { if (!isNoFinalMessage(e) || attempt === 1) throw e; }\n}","preventionTips":["Log raw provider responses during development to spot empty streams early","Keep stream adapters simple — throwing inside streamFn after the call starts produces this","Retry once on empty-stream errors before escalating"],"tags":["provider","empty-response","evidence"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}