ruvnet/ruflo · error · PodTemplateValidationError
pod-template at ${path}: allowedMcpTools entries must be non
Error message
pod-template at ${path}: allowedMcpTools entries must be non-empty strings What it means
Thrown inside the allowedMcpTools array item validator when an individual entry is not a non-empty string. Each entry in allowedMcpTools is an MCP tool name that the pod's agents may invoke, so it must be a meaningful string identifier.
Source
Thrown at v3/@claude-flow/cli/src/business-pods/pod-schema.ts:209
const name = requireString(json, 'name', '/');
if (!/^[a-z][a-z0-9-]*$/.test(name)) {
throw new PodTemplateValidationError('name must be lowercase-kebab (e.g. "sales")', '/');
}
const displayName = requireString(json, 'displayName', '/');
const roomId = requireString(json, 'roomId', '/');
if (!/^[A-Za-z0-9_.\-:/@#]+$/.test(roomId)) {
throw new PodTemplateValidationError(
'roomId may only contain [A-Za-z0-9_.\\-:/@#]',
'/',
);
}
const agents = requireArray(json, 'agents', '/', validatePodAgent);
if (agents.length === 0) {
throw new PodTemplateValidationError('agents must have ≥1 entry', '/');
}
const allowedMcpTools = requireArray(json, 'allowedMcpTools', '/', (t, tp) => {
if (typeof t !== 'string' || t.length === 0) {
throw new PodTemplateValidationError(
'allowedMcpTools entries must be non-empty strings',
tp,
);
}
return t;
});
if (allowedMcpTools.length === 0) {
throw new PodTemplateValidationError('allowedMcpTools must have ≥1 entry', '/');
}
const bench = validatePodBench(json.bench, '/bench');
const piiPolicy = requireString(json, 'piiPolicy', '/');
if (!PII_POLICIES.includes(piiPolicy as PiiPolicy)) {
throw new PodTemplateValidationError(
`piiPolicy must be one of: ${PII_POLICIES.join(', ')}`,
'/',
);
}
const budgetUsdMonthly = requireNumber(json, 'budgetUsdMonthly', '/');View on GitHub (pinned to 6b01dc5a68)
Solutions
- Replace the offending entry with a non-empty MCP tool name string (e.g. 'memory_search', 'swarm_init')
- Remove null or empty entries from the allowedMcpTools array
- Check the JSON-pointer path in the error to find the exact array index
Example fix
// before
{ "allowedMcpTools": ["memory_search", "", "swarm_init"] }
// after
{ "allowedMcpTools": ["memory_search", "swarm_init"] } Defensive patterns
Strategy: validation
Validate before calling
function areValidMcpToolEntries(tools: unknown[]): boolean {
return tools.every(t => typeof t === 'string' && t.length > 0);
}
if (!areValidMcpToolEntries(template.allowedMcpTools)) {
throw new Error('allowedMcpTools entries must be non-empty strings');
} Type guard
function isNonEmptyStringArray(arr: unknown): arr is string[] {
return Array.isArray(arr) && arr.every(item => typeof item === 'string' && item.length > 0);
} Try / catch
try {
validatePodTemplate(json);
} catch (e) {
if (e instanceof PodTemplateValidationError && e.message.includes('allowedMcpTools entries')) {
// Fix the specific array index indicated by e.path
}
} Prevention
- Use the JSON-pointer path in the error (e.g. /allowedMcpTools[2]) to find the exact bad entry
- Never leave empty string placeholders in allowedMcpTools
- Remove null or undefined entries that may result from YAML conversion
When it happens
Trigger: The allowedMcpTools array contains a non-string element (number, boolean, null, object) or an empty string. The error path (tp) points to the specific array index, e.g. /allowedMcpTools[2].
Common situations: A tool name was left as an empty string placeholder; a YAML converter produced a null entry; a trailing comma in a JSON5 source produced an undefined/null element.
Related errors
- pod-template at ${path}: allowedMcpTools must have ≥1 entry
- pod-template at ${path}: field "${key}" must be a non-empty
- pod-template at ${path}: field "${key}" must be a finite num
- pod-template at ${path}: field "${key}" must be a boolean
- pod-template at ${path}: field "${key}" must be an array
AI-assisted analysis of ruvnet/ruflo@6b01dc5a68 (2026-08-12).
Data as JSON: /api/errors/9de0e1ac06b1a11f.
Report an issue: GitHub.