ruvnet/ruflo · error · PodTemplateValidationError

pod-template at ${path}: allowedMcpTools must have ≥1 entry

Error message

pod-template at ${path}: allowedMcpTools must have ≥1 entry

What it means

Thrown by validatePodTemplate() when the allowedMcpTools array is present and all entries are valid strings, but the array has zero entries. A pod must allow at least one MCP tool — an empty allow-list means agents cannot perform any external actions.

Source

Thrown at v3/@claude-flow/cli/src/business-pods/pod-schema.ts:217

      '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', '/');
  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) {

View on GitHub (pinned to 6b01dc5a68)

Solutions

  1. Add at least one MCP tool name to the allowedMcpTools array (e.g. 'memory_search', 'task_create')
  2. Review which MCP tools the pod's agents genuinely need and add them

Example fix

// before
{ "allowedMcpTools": [] }

// after
{ "allowedMcpTools": ["memory_search", "hooks_route"] }
Defensive patterns

Strategy: validation

Validate before calling

if (!Array.isArray(template.allowedMcpTools) || template.allowedMcpTools.length === 0) {
  throw new Error('allowedMcpTools must have at least one entry');
}

Type guard

function hasAllowedMcpTools(template: unknown): boolean {
  return typeof template === 'object' && template !== null &&
    Array.isArray((template as Record<string, unknown>).allowedMcpTools) &&
    ((template as Record<string, unknown>).allowedMcpTools as unknown[]).length > 0;
}

Try / catch

try {
  validatePodTemplate(json);
} catch (e) {
  if (e instanceof PodTemplateValidationError && e.message.includes('allowedMcpTools must have')) {
    // Add at least one MCP tool name
  }
}

Prevention

When it happens

Trigger: The pod-template JSON has "allowedMcpTools": [] — a valid but empty array. Each entry passed the item validator (there are none), then the length check fails.

Common situations: All tool entries were removed during a security tightening pass but none were kept; the template was copied from a minimal example that omitted the tools list.

Related errors


AI-assisted analysis of ruvnet/ruflo@6b01dc5a68 (2026-08-12). Data as JSON: /api/errors/74862f49aeb279f1. Report an issue: GitHub.