ruvnet/ruflo · error · PodTemplateValidationError

pod-template at ${path}: budgetUsdPerRun must be ≥0

Error message

pod-template at ${path}: budgetUsdPerRun must be ≥0

What it means

Thrown by validatePodTemplate() when budgetUsdPerRun is a valid finite number but is negative. This value drives the reservation amount for each pod tick, so it must be zero or positive.

Source

Thrown at v3/@claude-flow/cli/src/business-pods/pod-schema.ts:233

  });
  if (allowedMcpTools.length === 0) {
    throw new PodTemplateValidationError('allowedMcpTools must have ≥1 entry', '/');
  }
  const bench = validatePodBench(json.bench, '/bench');
  const piiPolicy = requireString(json, 'piiPolicy', '/');
  if (!PII_POLICIES.includes(piiPolicy as PiiPolicy)) {
    throw new PodTemplateValidationError(
      `piiPolicy must be one of: ${PII_POLICIES.join(', ')}`,
      '/',
    );
  }
  const budgetUsdMonthly = requireNumber(json, 'budgetUsdMonthly', '/');
  if (budgetUsdMonthly < 0) {
    throw new PodTemplateValidationError('budgetUsdMonthly must be ≥0', '/');
  }
  const budgetUsdPerRun = requireNumber(json, 'budgetUsdPerRun', '/');
  if (budgetUsdPerRun < 0) {
    throw new PodTemplateValidationError('budgetUsdPerRun must be ≥0', '/');
  }
  if (budgetUsdMonthly > 0 && budgetUsdPerRun > budgetUsdMonthly) {
    throw new PodTemplateValidationError(
      'budgetUsdPerRun must not exceed budgetUsdMonthly',
      '/',
    );
  }
  const preferLocalExecution = requireBoolean(json, 'preferLocalExecution', '/');
  const cronSchedule = requireString(json, 'cronSchedule', '/');
  if (!CRON_RE.test(cronSchedule)) {
    throw new PodTemplateValidationError(
      'cronSchedule must be a POSIX cron expression (5 or 6 fields)',
      '/',
    );
  }
  const auditReadView = validateAuditReadView(json.auditReadView, '/auditReadView');

  let reservationExpiryMs: number | undefined;

View on GitHub (pinned to 6b01dc5a68)

Solutions

  1. Set budgetUsdPerRun to 0 or a positive dollar amount (e.g. 0.50)
  2. Use 0 rather than -1 for 'no per-run budget'

Example fix

// before
{ "budgetUsdPerRun": -0.05 }

// after
{ "budgetUsdPerRun": 0.05 }
Defensive patterns

Strategy: validation

Validate before calling

if (typeof template.budgetUsdPerRun !== 'number' || template.budgetUsdPerRun < 0) {
  throw new Error('budgetUsdPerRun must be >= 0');
}

Type guard

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

Try / catch

try {
  validatePodTemplate(json);
} catch (e) {
  if (e instanceof PodTemplateValidationError && e.message.includes('budgetUsdPerRun must be')) {
    // Set budgetUsdPerRun to 0 or a positive number
  }
}

Prevention

When it happens

Trigger: The budgetUsdPerRun field is set to any negative number. The requireNumber helper already verified it is finite; this check rejects negative amounts.

Common situations: A negative value was used as a 'not configured' sentinel; a sign error from a cost-estimation script.

Related errors


AI-assisted analysis of ruvnet/ruflo@6b01dc5a68 (2026-08-12). Data as JSON: /api/errors/b899f10b59164996. Report an issue: GitHub.