{"record":{"id":"42933e78e4b8d70c","repo":"ruvnet/ruflo","slug":"selectagentbackend-pod-must-be-a-validated-podtem","errorCode":null,"errorMessage":"selectAgentBackend: pod must be a validated PodTemplate object","messagePattern":"selectAgentBackend: pod must be a validated PodTemplate object","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/business-pods/domain-affinity-policy.ts","lineNumber":53,"sourceCode":"/** Structured routing decision. `reason` is rendered into the routing\n *  rationale via `hooks_explain` so operators can see why each pod was\n *  routed where it was. */\nexport interface BackendDecision {\n  backend: AgentBackend;\n  reason: string;\n}\n\n/**\n * Decide which backend `@metaharness/router` should prefer for a pod tick.\n *\n * @param pod  A validated PodTemplate. Validation is the caller's\n *             responsibility; this function will throw on malformed input\n *             (specifically on missing `preferLocalExecution` or\n *             `budgetUsdMonthly`).\n */\nexport function selectAgentBackend(pod: PodTemplate): BackendDecision {\n  if (pod === null || typeof pod !== 'object') {\n    throw new TypeError('selectAgentBackend: pod must be a validated PodTemplate object');\n  }\n  if (typeof pod.preferLocalExecution !== 'boolean') {\n    throw new TypeError(\n      'selectAgentBackend: pod.preferLocalExecution must be boolean (validate via pod-schema first)',\n    );\n  }\n  if (typeof pod.budgetUsdMonthly !== 'number' || !Number.isFinite(pod.budgetUsdMonthly)) {\n    throw new TypeError(\n      'selectAgentBackend: pod.budgetUsdMonthly must be a finite number (validate via pod-schema first)',\n    );\n  }\n\n  if (pod.preferLocalExecution) {\n    return {\n      backend: 'local-stdio',\n      reason: `pod \"${pod.name}\" preferLocalExecution=true — domain-affinity policy pins to local stdio`,\n    };\n  }","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/ruvnet/ruflo/blob/6b01dc5a687b26b3e218f796de45ec51f8fa9e8c/v3/@claude-flow/cli/src/business-pods/domain-affinity-policy.ts#L35-L71","documentation":"Defensive TypeError at the top of selectAgentBackend(). Fires when the pod argument is null or not an object at all (string, number, undefined). The function's JSDoc states validation is the caller's responsibility and expects a PodTemplate already passed through validatePodTemplate(). This guard catches the case where a caller skipped validation entirely and passed a raw JSON string, null, or undefined.","triggerScenarios":"Calling selectAgentBackend(pod) where pod is null, undefined, a string, a number, or any non-object primitive. Happens when a caller reads a pod template JSON file but passes the raw string, or passes undefined from a failed lookup, before validating.","commonSituations":"A pod loader returned undefined (file not found) and the caller forwarded it without checking; a JSON.parse result was passed directly without validation; a Map.get() returned undefined for a missing key.","solutions":["Always run the pod through validatePodTemplate() before calling selectAgentBackend() — it returns a typed PodTemplate or throws PodTemplateValidationError","Null-check the result of any loader/lookup before passing it to selectAgentBackend()"],"exampleFix":"// before:\nconst raw = fs.readFileSync(path, 'utf8');\nconst decision = selectAgentBackend(raw); // string, throws TypeError\n\n// after:\nconst pod = validatePodTemplate(JSON.parse(fs.readFileSync(path, 'utf8')));\nconst decision = selectAgentBackend(pod);","handlingStrategy":"validation","validationCode":"import { validatePodTemplate, type PodTemplate } from '@claude-flow/cli/business-pods/pod-schema';\n\n// Always validate the raw JSON first — validatePodTemplate returns a typed\n// PodTemplate or throws PodTemplateValidationError. Passing the result to\n// selectAgentBackend guarantees the object-shape guard never fires.\nconst pod: PodTemplate = validatePodTemplate(JSON.parse(rawJsonString));\nconst decision = selectAgentBackend(pod);","typeGuard":"import type { PodTemplate } from '@claude-flow/cli/business-pods/pod-schema';\n\nfunction isPodTemplate(v: unknown): v is PodTemplate {\n  return v !== null && typeof v === 'object'\n    && typeof (v as PodTemplate).preferLocalExecution === 'boolean'\n    && typeof (v as PodTemplate).budgetUsdMonthly === 'number';\n}","tryCatchPattern":null,"preventionTips":["Always run validatePodTemplate() on any externally loaded pod JSON before passing it to routing or execution","Never pass the raw output of fs.readFileSync or a failed Map.get() to selectAgentBackend"],"tags":["routing","validation","pod-template","type-guard"],"backgroundTag":null,"analyzedSha":"6b01dc5a687b26b3e218f796de45ec51f8fa9e8c","analyzedAt":"2026-08-12T13:20:50.148Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}