ruvnet/ruflo · error

estimatedUsd must be a non-negative finite number

Error message

estimatedUsd must be a non-negative finite number

What it means

BBS budget tracker reserve() rejects its estimatedUsd argument before opening the BEGIN IMMEDIATE transaction unless it is a finite, non-negative number. This guards the atomic budget-check-and-reserve path (ADR-164.1 §5.2) from NaN/Infinity/negative estimates that would corrupt ledger arithmetic.

Solutions

  1. Pass a finite non-negative number: clamp or default the estimate, e.g. Number.isFinite(est) && est >= 0 ? est : 0
  2. Fix upstream NaN sources: guard divisions and parseFloat results before they reach reserve()
  3. If cost is genuinely unknown, reserve 0 and commit the actual cost later via commit()
  4. Coerce string amounts with Number(...) and validate before calling

Example fix

// before
tracker.reserve(roomId, callerId, tokens / pricePerToken /* pricePerToken=0 => Infinity */);
// after
const est = Number.isFinite(tokens / pricePerToken) ? Math.max(0, tokens / pricePerToken) : 0;
tracker.reserve(roomId, callerId, est);
Defensive patterns

Strategy: validation

Validate before calling

function toReservationUsd(v: unknown): number {
  const n = typeof v === 'number' ? v : Number(v);
  if (!Number.isFinite(n) || n < 0) return 0; // or throw your own upstream error
  return n;
}
tracker.reserve(roomId, callerId, toReservationUsd(rawEstimate));

Type guard

function isReservationUsd(v: unknown): v is number {
  return typeof v === 'number' && Number.isFinite(v) && v >= 0;
}

Prevention

When it happens

Trigger: Calling tracker.reserve(roomId, callerId, estimatedUsd) where estimatedUsd is NaN (0/0, parseFloat('n/a')), Infinity (division by zero cost estimate), a negative number (credit math applied too early), or a numeric string ('4.20') since TypeScript types don't exist at runtime.

Common situations: Cost model returning NaN when a provider price list entry is missing; dividing by a zero token count; JSON config carrying a string amount; unit tests passing -1 as a sentinel for 'unknown cost'.

Related errors


AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18). Data as JSON: /api/errors/275241228879899d. Report an issue: GitHub.

Appendix: source

Thrown at v3/@claude-flow/cli/src/business-pods/bbs-budget-tracker.ts:193

        `INSERT INTO bbs_budget_rooms (room_id, monthly_cap_usd, billing_month, _lock_bump)
         VALUES (?, ?, ?, 0)
         ON CONFLICT(room_id) DO UPDATE SET monthly_cap_usd = excluded.monthly_cap_usd`,
      )
      .run(roomId, monthlyCapUsd, billingMonth);
  }

  /**
   * Atomically check budget and insert a reservation row in a single
   * BEGIN IMMEDIATE transaction. See ADR-164.1 §5.2.
   */
  reserve(
    roomId: string,
    callerId: string,
    estimatedUsd: number,
    opts?: { auditEnvelopeId?: string; expiryMs?: number },
  ): ReserveResult {
    if (!Number.isFinite(estimatedUsd) || estimatedUsd < 0) {
      throw new Error('estimatedUsd must be a non-negative finite number');
    }
    const auditEnvelopeId = opts?.auditEnvelopeId ?? `audit-${randomUUID()}`;
    const expiryMs = clampReservationExpiry(opts?.expiryMs ?? this.defaultExpiryMs);

    const nowMs = this.clock();
    const billingMonth = currentBillingMonth(nowMs);
    const billingMonthStart = billingMonthStartMs(billingMonth);

    const beginStmt = this.db.prepare('BEGIN IMMEDIATE');
    const commitStmt = this.db.prepare('COMMIT');
    const rollbackStmt = this.db.prepare('ROLLBACK');

    beginStmt.run();
    let transactionOpen = true;
    try {
      // Step 1: touch the room header row (the _lock_bump write makes the
      // lock acquisition visible per §3.2 peer-review note).
      const bumpRes = this.db

View on GitHub (pinned to fa13ee4ad6)