ruvnet/ruflo · error

worker policy denied: ${decision.reason ?? 'unknown reason'}

Error message

worker policy denied: ${decision.reason ?? 'unknown reason'}

What it means

Before spawning each worker, authorizeWorker shells out to `npx ruflo@latest policy evaluate` with the worker's identity, a swarm.worker.spawn action over its worktree/project path, and its capability envelope. The policy engine returns a decision object; any outcome other than enforcedOutcome === 'allowed' aborts the spawn with this error, including the engine's reason when present. Note this error specifically means the engine answered with a non-allowed decision — a missing ruflo binary or non-JSON output fails differently (command failure or JSON.parse error).

Source

Thrown at v3/@claude-flow/codex/src/dual-mode/orchestrator.ts:543

        type: 'swarm.worker.spawn',
        resource: worker.worktreePath ?? this.config.projectPath,
        tool: worker.platform,
        concurrency: 1,
        network: false,
        destructive: false,
      },
      context: {
        metadata: { childCapabilityEnvelope: envelope },
      },
    };
    const raw = await this.runCommand(
      'npx',
      ['ruflo@latest', 'policy', 'evaluate', JSON.stringify(request)],
      this.config.projectPath,
    );
    const decision = JSON.parse(raw) as { enforcedOutcome?: string; reason?: string };
    if (decision.enforcedOutcome !== 'allowed') {
      throw new Error(`worker policy denied: ${decision.reason ?? 'unknown reason'}`);
    }
    worker.capabilityEnvelope = envelope;
  }

  private defaultWorkerEnvelope(worker: WorkerConfig): WorkerCapabilityEnvelope {
    return {
      actions: ['*'],
      resources: ['*'],
      tools: ['*'],
      maxConcurrency: 1,
      network: false,
      destructive: false,
      delegationDepth: 0,
      expiresAt: Date.now() + this.config.timeout,
    };
  }

  private resolveWorkerEnvelope(worker: WorkerConfig): WorkerCapabilityEnvelope {

View on GitHub (pinned to fa13ee4ad6)

Solutions

  1. Read the reason embedded in the message — it comes straight from the policy decision and usually names the failing rule or capability
  2. Run `npx ruflo policy status` and `npx ruflo policy verify` in the project to inspect the active mode and rule set
  3. Shrink the worker's capabilityEnvelope (no network/destructive, fewer actions/tools) or point the worker at a resource path the policy grants for its role
  4. If the denial is correct, keep the policy and cancel dependent sibling work instead of trying to bypass the decision point
Defensive patterns

Strategy: try-catch

Validate before calling

import { spawnSync } from 'node:child_process';
function previewPolicyDecision(projectPath: string, request: object): { enforcedOutcome?: string; reason?: string } | null {
  const res = spawnSync('npx', ['ruflo@latest', 'policy', 'evaluate', JSON.stringify(request)],
    { cwd: projectPath, encoding: 'utf8' });
  if (res.status !== 0) return null;
  try { return JSON.parse(res.stdout); } catch { return null; }
}

Try / catch

try { await orchestrator.run(...); } catch (error) { if (error instanceof Error && error.message.startsWith('worker policy denied')) { const reason = error.message.slice('worker policy denied: '.length); /* cancel dependent siblings, surface reason to user */ } throw error; } — never catch-and-continue past a policy denial.

Prevention

When it happens

Trigger: A Ruflo policy in enforce mode denies swarm.worker.spawn for the worker's role, resource path, or platform; the requested capability envelope exceeds what policy grants to the principal; or the engine emits a deny/observe outcome with no reason field (message then shows 'unknown reason').

Common situations: Running a swarm in a repo whose policy config protects the paths the worker writes to; a session principal (CLAUDE_FLOW_PRINCIPAL_ID) not covered by any allow rule; upgrading ruflo so previously-tolerated actions now require explicit grants.

Related errors


AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18). Data as JSON: /api/errors/508a14ad38632346. Report an issue: GitHub.