JuliusBrussee/caveman · error · Error

cave_budget_output_floor_invalid

Error message

cave_budget_output_floor_invalid

What it means

Thrown by normalizeRunBudget when outputFloorTokens is not a safe integer or is not positive. The output floor is the minimum output-token headroom the runtime reserves on each call; a zero, negative, fractional, or non-numeric floor makes that clamp meaningless, so it is rejected. The field is optional and defaults to OUTPUT_CLAMP_FLOOR_TOKENS, so this only fires when a caller overrides it badly.

Source

Thrown at packages/agent/src/budget.ts:112

  const denomination: BudgetDenomination = usd ? "usd" : "tokens";
  const max = usd ? budget.maxUsd! : budget.maxTokens!;
  if (!Number.isFinite(max) || max <= 0) throw new Error("cave_budget_max_invalid");
  if (denomination === "tokens" && !Number.isSafeInteger(max)) {
    throw new Error("cave_budget_max_invalid");
  }
  const wrongInitial = denomination === "usd" ? budget.initialTokens : budget.initialUsd;
  if (wrongInitial !== undefined) throw new Error("cave_budget_denomination_ambiguous");
  const declaredInitial = denomination === "usd" ? budget.initialUsd : budget.initialTokens;
  const initial = declaredInitial ?? max;
  if (!Number.isFinite(initial) || initial <= 0 || initial > max) {
    throw new Error("cave_budget_initial_invalid");
  }
  if (denomination === "tokens" && !Number.isSafeInteger(initial)) {
    throw new Error("cave_budget_initial_invalid");
  }
  const outputFloorTokens = budget.outputFloorTokens ?? OUTPUT_CLAMP_FLOOR_TOKENS;
  if (!Number.isSafeInteger(outputFloorTokens) || outputFloorTokens <= 0) {
    throw new Error("cave_budget_output_floor_invalid");
  }
  const onExhausted = budget.onExhausted ?? "compact";
  if (onExhausted !== "compact" && onExhausted !== "stop") {
    throw new Error("cave_budget_on_exhausted_invalid");
  }
  return Object.freeze({
    denomination,
    max,
    initial,
    outputFloorTokens,
    onExhausted,
    compaction: normalizeCompaction(budget.compaction),
  });
}

/** Identity and shape of one prospective provider call. */
export interface CallCeiling {
  readonly provider: string;

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. If you need a different floor, pass a positive safe integer (e.g. outputFloorTokens: 2048).
  2. To use the built-in default, omit the field entirely rather than passing 0.
  3. Validate env-derived values: Number.isSafeInteger(n) && n > 0 before including them in the budget.

Example fix

// before
const budget = { maxUsd: 5, outputFloorTokens: 0 }; // attempting to disable the floor

// after
const budget = { maxUsd: 5, outputFloorTokens: 2048 };
Defensive patterns

Strategy: validation

Validate before calling

const floor = process.env.OUTPUT_FLOOR !== undefined ? Number(process.env.OUTPUT_FLOOR) : undefined;
const budget = {
  maxUsd: 5,
  ...(floor !== undefined && Number.isSafeInteger(floor) && floor > 0 ? { outputFloorTokens: floor } : {}),
};

Type guard

function isValidOutputFloor(v: unknown): v is number {
  return typeof v === "number" && Number.isSafeInteger(v) && v > 0;
}

Prevention

When it happens

Trigger: Passing outputFloorTokens: 0 (attempting to disable the clamp); passing a float like 512.5; passing NaN or a negative number; passing a numeric string such as "1024".

Common situations: Tuning the floor from an env var without validating the parse; copying a fractional default from documentation or a blog post; attempting to disable output clamping entirely by setting the floor to zero.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15). Data as JSON: /api/errors/9dc77ceb7c76e5e8. Report an issue: GitHub.