JuliusBrussee/caveman · error · Error

cave_eve_usage_missing

cave_eve_usage_missing

Error message

cave_eve_usage_missing

What it means

`usageFromEveEvents` aggregates usage from every `step.completed` event; after the loop it throws (line 433) if zero `step.completed` events with data were seen OR if the plan requires reasoning accounting (`plan.reasoning !== "none"`). The Eve durable event contract carries no reasoning-token split, so reasoning-capable plans are structurally unsupported on this adapter — Eve only serves reasoning-off locks — and a session with no billable steps likewise cannot produce usage evidence.

Solutions

  1. Set the plan's reasoning to `"none"` (a reasoning-off lock) for Eve runs
  2. Verify the session's events contain `step.completed` entries with `data.usage`
  3. Confirm the runtime really is Eve 0.29.2 so the event contract matches what the adapter parses

Example fix

// before
const plan = await compile({ ...opts, reasoning: 'per-turn' }); // Eve adapter rejects
// after
const plan = await compile({ ...opts, reasoning: 'none' });
Defensive patterns

Strategy: validation

Validate before calling

// Eve's event contract omits reasoning usage: enforce reasoning-off plans
// before wiring the adapter
if (plan.reasoning !== 'none') {
  throw new Error(`eve adapter requires reasoning: 'none' plans, got '${plan.reasoning}'`);
}
return createEveAdapter(identity, session);

Try / catch

try {
  return await adapter.run(req);
} catch (e) {
  if (e instanceof Error && e.message === 'cave_eve_usage_missing' && plan.reasoning !== 'none') {
    // structural: recompile the plan with reasoning 'none' for the Eve lane
    return runOnce({ ...req, plan: await compile({ ...opts, reasoning: 'none' }) });
  }
  throw e;
}

Prevention

When it happens

Trigger: Compiling a plan with reasoning enabled and running it through `createEveAdapter` (always throws); an Eve run that completed without emitting any `step.completed` events because the event log was filtered, empty, or short-circuited.

Common situations: Copying a reasoning plan from the Pi/Vercel lane into the Eve lane; event middleware with an allowlist that drops step events; Eve version drift changing the event contract (the adapter pins 0.29.2).

Related errors


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

Appendix: source

Thrown at packages/agent/src/adapters.ts:433

  }, reasoningRequired, "cave_mastra_usage_missing");
}

function usageFromEveEvents(events: unknown[], reasoningRequired: boolean): NormalizedUsage {
  let totalInputTokens = 0;
  let outputTokens = 0;
  let cacheReadTokens = 0;
  let cacheWriteTokens = 0;
  let steps = 0;
  for (const event of events) {
    if (!isRecord(event) || event.type !== "step.completed" || !isRecord(event.data)) continue;
    const usage = record(event.data.usage, "cave_eve_usage_missing");
    totalInputTokens += strictInteger(usage.inputTokens, "cave_eve_usage_missing");
    outputTokens += strictInteger(usage.outputTokens, "cave_eve_usage_missing");
    cacheReadTokens += strictInteger(usage.cacheReadTokens, "cave_eve_usage_missing");
    cacheWriteTokens += strictInteger(usage.cacheWriteTokens, "cave_eve_usage_missing");
    steps++;
  }
  if (steps === 0 || reasoningRequired) throw new Error("cave_eve_usage_missing");
  if (cacheReadTokens + cacheWriteTokens > totalInputTokens) {
    throw new Error("cave_eve_usage_missing");
  }
  const inputTokens = totalInputTokens - cacheReadTokens - cacheWriteTokens;
  return normalizeUsage({
    inputTokens,
    outputTokens,
    cacheReadTokens,
    cacheWriteTokens,
    reasoningTokens: 0,
    totalTokens: inputTokens + outputTokens + cacheReadTokens + cacheWriteTokens,
  }, false, "cave_eve_usage_missing");
}

function normalizeUsage(
  value: Record<keyof NormalizedUsage, unknown>,
  reasoningRequired: boolean,
  error: string,

View on GitHub (pinned to 766dce6b13)