{"record":{"id":"5cb53184b413aef6","repo":"ruvnet/ruflo","slug":"budgetusdperrun-must-be-0","errorCode":null,"errorMessage":"budgetUsdPerRun must be ≥0","messagePattern":"budgetUsdPerRun must be ≥0","errorType":"validation","errorClass":"PodTemplateValidationError","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/business-pods/pod-schema.ts","lineNumber":233,"sourceCode":"  });\n  if (allowedMcpTools.length === 0) {\n    throw new PodTemplateValidationError('allowedMcpTools must have ≥1 entry', '/');\n  }\n  const bench = validatePodBench(json.bench, '/bench');\n  const piiPolicy = requireString(json, 'piiPolicy', '/');\n  if (!PII_POLICIES.includes(piiPolicy as PiiPolicy)) {\n    throw new PodTemplateValidationError(\n      `piiPolicy must be one of: ${PII_POLICIES.join(', ')}`,\n      '/',\n    );\n  }\n  const budgetUsdMonthly = requireNumber(json, 'budgetUsdMonthly', '/');\n  if (budgetUsdMonthly < 0) {\n    throw new PodTemplateValidationError('budgetUsdMonthly must be ≥0', '/');\n  }\n  const budgetUsdPerRun = requireNumber(json, 'budgetUsdPerRun', '/');\n  if (budgetUsdPerRun < 0) {\n    throw new PodTemplateValidationError('budgetUsdPerRun must be ≥0', '/');\n  }\n  if (budgetUsdMonthly > 0 && budgetUsdPerRun > budgetUsdMonthly) {\n    throw new PodTemplateValidationError(\n      'budgetUsdPerRun must not exceed budgetUsdMonthly',\n      '/',\n    );\n  }\n  const preferLocalExecution = requireBoolean(json, 'preferLocalExecution', '/');\n  const cronSchedule = requireString(json, 'cronSchedule', '/');\n  if (!CRON_RE.test(cronSchedule)) {\n    throw new PodTemplateValidationError(\n      'cronSchedule must be a POSIX cron expression (5 or 6 fields)',\n      '/',\n    );\n  }\n  const auditReadView = validateAuditReadView(json.auditReadView, '/auditReadView');\n\n  let reservationExpiryMs: number | undefined;","sourceCodeStart":215,"sourceCodeEnd":251,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/cli/src/business-pods/pod-schema.ts#L215-L251","documentation":"The top-level budgetUsdPerRun number must be >= 0. As with the monthly field, zero is valid (no per-run cap) and only negative values are rejected here; non-numeric values fail earlier inside requireNumber with a different message.","triggerScenarios":"A template with budgetUsdPerRun set to a negative number (e.g. -0.5). Reaching this specific message means requireNumber succeeded and the value is negative.","commonSituations":"Copy-paste from a 'credits remaining' style config where negatives were possible; converting cents to dollars with a sign slip; sentinel -1 'unlimited' conventions from other systems.","solutions":["Set budgetUsdPerRun to 0 for 'no per-run cap', or a positive dollar amount","Check that the value is in USD (not cents) and positively signed","Remember the follow-up constraint: if budgetUsdMonthly > 0, budgetUsdPerRun must not exceed it"],"exampleFix":"// before\n\"budgetUsdPerRun\": -0.01\n// after\n\"budgetUsdPerRun\": 0.5","handlingStrategy":"validation","validationCode":"if (typeof json.budgetUsdPerRun !== 'number' || json.budgetUsdPerRun < 0) {\n  json.budgetUsdPerRun = Math.max(0, Number(json.budgetUsdPerRun) || 0);\n}","typeGuard":"function isValidBudget(v: unknown): v is number {\n  return typeof v === 'number' && Number.isFinite(v) && v >= 0;\n}","tryCatchPattern":"try { validatePodTemplate(json); } catch (err) {\n  if (err instanceof PodTemplateValidationError && /budgetUsdPerRun/.test(err.message)) {\n    // fix sign/unit, then also check per-run <= monthly when monthly > 0\n  }\n}","preventionTips":["Keep both budget fields in USD dollars, never cents or credits","After fixing per-run, re-run validation to catch the cross-field check next"],"tags":["schema-validation","business-pods","budget","configuration"],"backgroundTag":"schema-validation-failed","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}