JuliusBrussee/caveman · error · Error
cave_transform_trace_basis_mixed
cave_transform_trace_basis_mixed
Error message
cave_transform_trace_basis_mixed
What it means
A turn bill sums before/after token counts over the transforms applied that turn, and a token delta is only meaningful within one measurement basis — `byte_derived` (local estimate) or `engine_counted` (loopback engine's own count). `turnBill` refuses to blend the two into a single reduction figure and throws this invariant error instead of publishing a dishonest number.
Source
Thrown at packages/agent/src/code.ts:785
// missing runtime does.
if (result.mode === "observe-only") degrade(session);
const record: TurnRecord = {
input,
text: result.text,
toolCalls: result.toolCalls,
bill: turnBill(session.turns.length + 1, result),
degraded: startedOptimized && session.mode === "observe-only",
};
session.turns.push(record);
return record;
}
function turnBill(turn: number, result: RunResult): TurnBill {
const applied = result.transformTrace.filter((item) => item.outcome === "applied");
// A token delta is only meaningful within one basis; refuse to blend
// byte-derived and engine-counted figures into a single reduction.
const bases = new Set(applied.map((item) => item.tokensBasis));
if (bases.size > 1) throw new Error("cave_transform_trace_basis_mixed");
const tokensBasis: TransformTrace["tokensBasis"] = applied[0]?.tokensBasis ?? "byte_derived";
const before = applied.reduce((sum, item) => sum + item.beforeTokens, 0);
const after = applied.reduce((sum, item) => sum + item.afterTokens, 0);
return {
turn,
mode: result.mode,
provider: result.provider,
model: result.model,
contextBill: result.contextBill,
transformedTokensBefore: before,
transformedTokensAfter: after,
// The reduction is the delta of what was ACTUALLY SENT, so a barely-
// compressible turn whose wrapper cost more than it saved reports zero
// rather than a phantom positive; the raw before/after stay exposed.
tokensSavedInferred: Math.max(0, before - after),
tokensBasis,
transformIDs: result.transformIDs,
transformFailures: result.transformFailures,View on GitHub (pinned to 766dce6b13)
Solutions
- Keep engine configuration uniform for the whole session: either run with the loopback engine the entire time or fully cold (observe-only), not a mix.
- Restart the session (`startCodingSession` again) after changing engine availability so the route pins one basis.
- If it reproduces with a stable configuration, capture `RunResult.transformTrace` and file an issue — per-turn basis uniformity is an internal contract.
Defensive patterns
Strategy: try-catch
Validate before calling
function hasMixedBases(result: RunResult): boolean {
const bases = new Set(
result.transformTrace
.filter((item) => item.outcome === "applied")
.map((item) => item.tokensBasis),
);
return bases.size > 1;
} Try / catch
try {
const record = await runCodingTurn(session, input);
} catch (error) {
if (error instanceof Error && error.message === "cave_transform_trace_basis_mixed") {
// billing invariant broke: keep the session, mark the token bill unavailable
session.notices.push("token bill unavailable: mixed token bases this turn");
return;
}
throw error;
} Prevention
- Do not start/stop the loopback engine between turns of one session.
- Treat a mixed-basis turn as a framework bug: capture transformTrace and report it.
When it happens
Trigger: A single run's `RunResult.transformTrace` contains applied entries with different `tokensBasis` values — typically part of the turn's transforms got engine token counts while another transform route (or a transform-failure recovery path) reported byte-derived figures. Surfaces from `runCodingTurn` when the turn record is billed.
Common situations: Engine/loopback runtime becomes available or drops mid-session so routes flip between counted and estimated; version skew between gateway and engine; usually indicates a framework bug worth reporting rather than a user config mistake.
Related errors
- cave_vercel_usage_missing
- cave_mastra_usage_missing
- cave_retry_accounting_invalid
- caveman agent: subagent maxTokens must be a positive integer
- cave_nested_usage_incomplete
AI-assisted analysis of JuliusBrussee/caveman@766dce6b13 (2026-08-18).
Data as JSON: /api/errors/7eb328c75c5ba03e.
Report an issue: GitHub.