{"record":{"id":"b993f0e9d1679de3","repo":"ruvnet/ruflo","slug":"budgetusdmonthly-must-be-0","errorCode":null,"errorMessage":"budgetUsdMonthly must be ≥0","messagePattern":"budgetUsdMonthly must be ≥0","errorType":"validation","errorClass":"PodTemplateValidationError","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/business-pods/pod-schema.ts","lineNumber":229,"sourceCode":"        tp,\n      );\n    }\n    return t;\n  });\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    );","sourceCodeStart":211,"sourceCodeEnd":247,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/cli/src/business-pods/pod-schema.ts#L211-L247","documentation":"The top-level budgetUsdMonthly number must be >= 0. Negative budgets are meaningless; zero is allowed and means 'no monthly cap' (note: the cross-field per-run check in error 193 only applies when budgetUsdMonthly > 0). requireNumber already rejected non-numbers, so this error is specifically a negative numeric value.","triggerScenarios":"A template with budgetUsdMonthly set to a negative number, e.g. -1 or -100. A string like \"-5\" would instead fail requireNumber with a missing/invalid-field error.","commonSituations":"Using -1 as a 'no budget / unlimited' sentinel the way other config systems do; sign typos; spreadsheet exports producing negative placeholder values.","solutions":["Use 0 to express 'no monthly budget' — it is the schema's intended unlimited/no-cap value","Fix sign errors: any positive USD amount is valid","If porting configs that use -1 for unlimited, translate -1 -> 0 in your template converter"],"exampleFix":"// before\n\"budgetUsdMonthly\": -1\n// after\n\"budgetUsdMonthly\": 0","handlingStrategy":"validation","validationCode":"if (typeof json.budgetUsdMonthly !== 'number' || json.budgetUsdMonthly < 0) {\n  json.budgetUsdMonthly = Math.max(0, Number(json.budgetUsdMonthly) || 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 && /budgetUsdMonthly/.test(err.message)) {\n    // map -1 'unlimited' sentinels to 0 and re-validate\n  }\n}","preventionTips":["Translate -1 'unlimited' sentinels to 0 when importing external configs","Validate budget fields with the same >= 0 rule in your template generator"],"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"}