{"record":{"id":"4af4819278c7e7a5","repo":"ruvnet/ruflo","slug":"allowedmcptools-entries-must-be-non-empty-strings","errorCode":null,"errorMessage":"allowedMcpTools entries must be non-empty strings","messagePattern":"allowedMcpTools entries must be non-empty strings","errorType":"validation","errorClass":"PodTemplateValidationError","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/business-pods/pod-schema.ts","lineNumber":209,"sourceCode":"  const name = requireString(json, 'name', '/');\n  if (!/^[a-z][a-z0-9-]*$/.test(name)) {\n    throw new PodTemplateValidationError('name must be lowercase-kebab (e.g. \"sales\")', '/');\n  }\n  const displayName = requireString(json, 'displayName', '/');\n  const roomId = requireString(json, 'roomId', '/');\n  if (!/^[A-Za-z0-9_.\\-:/@#]+$/.test(roomId)) {\n    throw new PodTemplateValidationError(\n      'roomId may only contain [A-Za-z0-9_.\\\\-:/@#]',\n      '/',\n    );\n  }\n  const agents = requireArray(json, 'agents', '/', validatePodAgent);\n  if (agents.length === 0) {\n    throw new PodTemplateValidationError('agents must have ≥1 entry', '/');\n  }\n  const allowedMcpTools = requireArray(json, 'allowedMcpTools', '/', (t, tp) => {\n    if (typeof t !== 'string' || t.length === 0) {\n      throw new PodTemplateValidationError(\n        'allowedMcpTools entries must be non-empty strings',\n        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', '/');","sourceCodeStart":191,"sourceCodeEnd":227,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/cli/src/business-pods/pod-schema.ts#L191-L227","documentation":"Each entry of the top-level allowedMcpTools array must be a non-empty string — the tool names the pod agent may invoke (an allowlist). Numbers, null, booleans, and \"\" are rejected at the entry's path (/allowedMcpTools/<index>). Note \"*\" is accepted as a regular non-empty string; the schema does not special-case it here.","triggerScenarios":"A template with allowedMcpTools containing 0 or other numbers (e.g. from enum indices), null holes, or empty strings produced by join/split bugs in template generation scripts.","commonSituations":"Programmatic template builders mapping tool IDs to indices; arrays built with Array(n).map(...) leaving undefined/null; trailing empty entries from splitting a delimited string on a trailing delimiter.","solutions":["Replace numeric/null entries with the actual MCP tool name strings","Filter out falsy entries: allowedMcpTools = allowedMcpTools.filter(t => typeof t === 'string' && t.length > 0)","Add a template unit test that asserts every entry is a non-empty string before validation"],"exampleFix":"// before\n\"allowedMcpTools\": [\"memory_store\", null, \"\"]\n// after\n\"allowedMcpTools\": [\"memory_store\", \"task_create\"]","handlingStrategy":"validation","validationCode":"json.allowedMcpTools = (json.allowedMcpTools as unknown[])\n  .filter((t): t is string => typeof t === 'string' && t.length > 0);","typeGuard":"function isNonEmptyStringArray(v: unknown): v is string[] {\n  return Array.isArray(v) && v.every(e => typeof e === 'string' && e.length > 0);\n}","tryCatchPattern":"try { validatePodTemplate(json); } catch (err) {\n  if (err instanceof PodTemplateValidationError && err.path.startsWith('/allowedMcpTools/')) {\n    // drop or fix the offending entry at the index in err.path, retry\n  }\n}","preventionTips":["Never build tool lists with Array(n).map — use explicit literals or filtered maps","Assert entries are strings in the generator's own unit tests"],"tags":["schema-validation","business-pods","mcp-tools","allowlist","configuration"],"backgroundTag":"schema-validation-failed","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}