paperclipai/paperclip · error

managed session spend ceiling must be positive

Error message

managed session spend ceiling must be positive

What it means

The managed budget update validates maxSessionListCostUsd is a finite number greater than 0 before sending session/budget/increase to the remote transport. Non-finite, zero, or negative ceilings are rejected client-side so an invalid budget never reaches the provider.

Source

Thrown at packages/paperclip-runner/src/live/live-session.ts:2073

    });
    await this.#persist();
    return this.snapshot();
  }

  async increaseManagedSessionBudget(
    maxSessionListCostUsd: number,
  ): Promise<CapabilityLiveSessionSnapshot> {
    if (
      (this.#config.provider !== "claude_managed" &&
        this.#config.provider !== "aws_agentcore") ||
      this.#transport === null
    ) {
      throw new Error(
        "remote session budget updates require a connected remote provider session",
      );
    }
    if (!Number.isFinite(maxSessionListCostUsd) || maxSessionListCostUsd <= 0) {
      throw new Error("managed session spend ceiling must be positive");
    }
    await this.#transport.request("session/budget/increase", {
      maxSessionListCostUsd,
    });
    if (this.#config.managedProfile) {
      this.#config.managedProfile.maxSessionListCostUsd = maxSessionListCostUsd;
    }
    if (this.#config.agentCoreProfile) {
      this.#config.agentCoreProfile.maxEstimatedSessionCostUsd =
        maxSessionListCostUsd;
    }
    this.#status = this.#activeTurnId === null ? "warm_idle" : "running";
    this.#appendEvidence("session", this.#activeTurnId, {
      action: "budget_increased",
      maxSessionListCostUsd,
    });
    await this.#persist();
    return this.snapshot();

View on GitHub (pinned to 01ad858492)

Solutions

  1. Pass a positive finite number for maxSessionListCostUsd
  2. Validate/parse the configured budget before calling; treat unset config as an error, not NaN
  3. Clamp or default the value (e.g. Number.isFinite(v) && v > 0 ? v : DEFAULT_CEILING)
  4. Fix the computation upstream that produced 0/NaN

Example fix

// before
const budget = Number(process.env.MAX_COST); // NaN if unset
await session.updateManagedRemoteSessionBudget(budget);
// after
const budget = Number(process.env.MAX_COST);
if (!Number.isFinite(budget) || budget <= 0) throw new Error('MAX_COST must be a positive USD amount');
await session.updateManagedRemoteSessionBudget(budget);
Defensive patterns

Strategy: validation

Validate before calling

if (!Number.isFinite(maxSessionListCostUsd) || maxSessionListCostUsd <= 0) throw new Error(`maxSessionListCostUsd must be a positive finite number, got ${maxSessionListCostUsd}`);

Type guard

function isValidBudgetUsd(v: number): boolean {
  return Number.isFinite(v) && v > 0;
}

Try / catch

try {
  await session.updateManagedRemoteSessionBudget(usd);
} catch (err) {
  if (err instanceof Error && err.message.includes('spend ceiling must be positive')) {
    // fix configured value and retry
  } else throw err;
}

Prevention

When it happens

Trigger: Calling the budget-update method with maxSessionListCostUsd = 0, negative, NaN, or Infinity (e.g. from unparsed config, missing env var, or division producing NaN).

Common situations: parseFloat of an unset env var yielding NaN; budget configured as 0 to 'disable' spend (unsupported); unit mismatch producing a tiny/negative computed value.

Related errors


AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-02). Data as JSON: /api/errors/af4d5fe44b344a40. Report an issue: GitHub.