JuliusBrussee/caveman · error · Error

cave_incomplete_evidence: Pi emitted no final assistant mess

Error message

cave_incomplete_evidence: Pi emitted no final assistant message

What it means

Evidence guard at the end of a streaming run: no final assistant message was emitted and no stop reason was recorded, so the run cannot prove what it spent or produced. This is a harness/protocol failure, not a user-input error.

Source

Thrown at packages/agent/src/runtime.ts:2107

    }
    if (ladderFailure) throw ladderFailure;
    if (spendFailure) throw spendFailure;
    if (usageFailure !== undefined &&
        (efficiencyPlan !== undefined ||
          executionContext.spendLedgers.length > 0 ||
          usageFailure.message === "cave_provider_model_identity_mismatch" ||
          usageFailure.message === "cave_provider_identity_missing")) {
      throw usageFailure;
    }
    if (pendingSpendReservations.length > 0) {
      markSpendIncomplete(executionContext.spendLedgers);
      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) {

View on GitHub (pinned to 766dce6b13)

Solutions

  1. Retry the run; a dropped stream or provider glitch can produce an empty transcript
  2. Check network/provider status that could truncate the response
  3. Report with the trace if it reproduces — it indicates an upstream SDK/provider bug
Defensive patterns

Strategy: retry

When it happens

Trigger: Thrown at packages/agent/src/runtime.ts:2107 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of JuliusBrussee/caveman@766dce6b13 (2026-08-18). Data as JSON: /api/errors/e239c28b3de2b62f. Report an issue: GitHub.