ruvnet/ruflo · error · TypeError
selectAgentBackend: pod.budgetUsdMonthly must be a finite nu
Error message
selectAgentBackend: pod.budgetUsdMonthly must be a finite number (validate via pod-schema first)
What it means
TypeError in selectAgentBackend() when pod.budgetUsdMonthly is missing, not a number, or not finite (NaN/±Infinity). This field is the threshold input for the routing decision (>= 50 routes to cloud-managed). A malformed value means the pod was not validated via validatePodTemplate() which enforces a finite number.
Source
Thrown at v3/@claude-flow/cli/src/business-pods/domain-affinity-policy.ts:61
/**
* Decide which backend `@metaharness/router` should prefer for a pod tick.
*
* @param pod A validated PodTemplate. Validation is the caller's
* responsibility; this function will throw on malformed input
* (specifically on missing `preferLocalExecution` or
* `budgetUsdMonthly`).
*/
export function selectAgentBackend(pod: PodTemplate): BackendDecision {
if (pod === null || typeof pod !== 'object') {
throw new TypeError('selectAgentBackend: pod must be a validated PodTemplate object');
}
if (typeof pod.preferLocalExecution !== 'boolean') {
throw new TypeError(
'selectAgentBackend: pod.preferLocalExecution must be boolean (validate via pod-schema first)',
);
}
if (typeof pod.budgetUsdMonthly !== 'number' || !Number.isFinite(pod.budgetUsdMonthly)) {
throw new TypeError(
'selectAgentBackend: pod.budgetUsdMonthly must be a finite number (validate via pod-schema first)',
);
}
if (pod.preferLocalExecution) {
return {
backend: 'local-stdio',
reason: `pod "${pod.name}" preferLocalExecution=true — domain-affinity policy pins to local stdio`,
};
}
if (pod.budgetUsdMonthly >= CLOUD_BUDGET_THRESHOLD_USD) {
return {
backend: 'cloud-managed',
reason:
`pod "${pod.name}" preferLocalExecution=false and budgetUsdMonthly=${pod.budgetUsdMonthly} ` +
`>= ${CLOUD_BUDGET_THRESHOLD_USD} — routes to cloud Managed Agents`,
};
}View on GitHub (pinned to 6b01dc5a68)
Solutions
- Run validatePodTemplate() — requireNumber() checks typeof === 'number' and Number.isFinite() before selectAgentBackend ever sees the value
- If constructing the object in code, ensure budgetUsdMonthly is a finite number literal
Example fix
// before:
selectAgentBackend({ ...pod, budgetUsdMonthly: Number("unlimited") }); // NaN, throws
// after:
const pod = validatePodTemplate(parsed);
selectAgentBackend(pod); // budgetUsdMonthly is a finite number Defensive patterns
Strategy: validation
Validate before calling
import { validatePodTemplate } from '@claude-flow/cli/business-pods/pod-schema';
// validatePodTemplate's requireNumber() enforces Number.isFinite for
// budgetUsdMonthly before selectAgentBackend ever sees the value.
const pod = validatePodTemplate(parsedJson);
selectAgentBackend(pod); Type guard
function hasValidBudgetUsdMonthly(pod: unknown): boolean {
if (typeof pod !== 'object' || pod === null) return false;
const v = (pod as { budgetUsdMonthly?: unknown }).budgetUsdMonthly;
return typeof v === 'number' && Number.isFinite(v);
} Prevention
- Validate pod templates via validatePodTemplate() before routing
- Ensure budget fields are written as bare JSON numbers, not quoted strings
- Guard against NaN from Number() coercion of non-numeric config values
When it happens
Trigger: Calling selectAgentBackend(pod) where pod.budgetUsdMonthly is undefined, a string like "50", NaN, or Infinity.
Common situations: Budget read from config as a string and not coerced; a missing field in a hand-written template; Number('unlimited') producing NaN; a computation that overflows to Infinity.
Related errors
- selectAgentBackend: pod must be a validated PodTemplate obje
- selectAgentBackend: pod.preferLocalExecution must be boolean
- pod-template at ${path}: field "${key}" must be a finite num
- pod-template at ${path}: bench.scheduleHours must be ≥1
- pod-template at ${path}: auditReadView.retentionDays must be
AI-assisted analysis of ruvnet/ruflo@6b01dc5a68 (2026-08-12).
Data as JSON: /api/errors/83ee168052968aae.
Report an issue: GitHub.