ruvnet/ruflo · error · PodTemplateValidationError
budgetUsdPerRun must not exceed budgetUsdMonthly
Error message
budgetUsdPerRun must not exceed budgetUsdMonthly
What it means
This is the raw constructor argument for the same budgetUsdPerRun > budgetUsdMonthly check. The string 'budgetUsdPerRun must not exceed budgetUsdMonthly' is the first argument to 'new PodTemplateValidationError(message, path)' before the constructor prepends 'pod-template at ${path}: '. A developer inspecting the throw site or the raw message field sees this form; the constructed Error.message includes the prefix.
Source
Thrown at v3/@claude-flow/cli/src/business-pods/pod-schema.ts:244
}
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;
if (json.reservationExpiryMs !== undefined) {
const v = requireNumber(json, 'reservationExpiryMs', '/');
// ADR-164.1 §3.2 — bounded to [5_000, 300_000] ms.
if (v < 5_000 || v > 300_000) {
throw new PodTemplateValidationError(
'reservationExpiryMs must be within [5000, 300000] ms (ADR-164.1 §3.2)',
'/',
);
}
reservationExpiryMs = v;
}View on GitHub (pinned to 6b01dc5a68)
Solutions
- Ensure budgetUsdPerRun <= budgetUsdMonthly when budgetUsdMonthly > 0
- Set budgetUsdMonthly to 0 to disable the monthly cap entirely
- Match on 'PodTemplateValidationError' name rather than the raw message string in catch blocks
Example fix
// before
{ "budgetUsdMonthly": 100, "budgetUsdPerRun": 150 }
// after
{ "budgetUsdMonthly": 0, "budgetUsdPerRun": 150 } Defensive patterns
Strategy: validation
Validate before calling
const monthly = template.budgetUsdMonthly;
const perRun = template.budgetUsdPerRun;
if (monthly > 0 && perRun > monthly) {
throw new Error('budgetUsdPerRun must not exceed budgetUsdMonthly');
} Type guard
function budgetsAreConsistent(monthly: number, perRun: number): boolean {
return monthly === 0 || perRun <= monthly;
} Try / catch
try {
validatePodTemplate(json);
} catch (e) {
if (e instanceof PodTemplateValidationError) {
// e.message includes 'pod-template at /: budgetUsdPerRun must not exceed budgetUsdMonthly'
// Match on e.name === 'PodTemplateValidationError' rather than raw message
}
} Prevention
- Match on PodTemplateValidationError.name rather than the raw constructor message string
- Ensure per-run budget does not exceed monthly budget when monthly > 0
- Use 0 for budgetUsdMonthly to skip this check entirely
When it happens
Trigger: budgetUsdMonthly > 0 && budgetUsdPerRun > budgetUsdMonthly. Same logical condition as the constructed error — the raw message is what the throw statement passes to the PodTemplateValidationError constructor.
Common situations: Same as the constructed form: per-run budget exceeds monthly cap when a monthly cap is active (>0). Encountered when inspecting source or matching against the raw message string in error-handling code that reads the constructor argument rather than .message.
Related errors
- pod-template at ${path}: budgetUsdMonthly must be ≥0
- pod-template at ${path}: budgetUsdPerRun must be ≥0
- pod-template at ${path}: budgetUsdPerRun must not exceed bud
- reservationExpiryMs must be within [5000, 300000] ms (ADR-16
- pod-template at ${path}: field "${key}" must be a non-empty
AI-assisted analysis of ruvnet/ruflo@6b01dc5a68 (2026-08-12).
Data as JSON: /api/errors/9e37e8813b4e3c98.
Report an issue: GitHub.