ruvnet/ruflo · error · Error

mode must be legacy, observe, or enforce

Error message

mode must be legacy, observe, or enforce

What it means

During `policy init`/`policy migrate`, the requested mode is validated against the fixed ADR-324 vocabulary legacy | observe | enforce before setPolicyMode is called. Any other string — including differently-cased ones — is rejected so the policy state file never records an unknown mode.

Solutions

  1. Use exactly one of legacy, observe, or enforce, all lowercase
  2. Check `ruflo policy status` to see the current mode and vocabulary
  3. If a positional was swallowed as the mode, move it to a flag or remove it

Example fix

# before
ruflo policy init --mode Enforce

# after
ruflo policy init --mode enforce
Defensive patterns

Strategy: validation

Validate before calling

const POLICY_MODES = ['legacy', 'observe', 'enforce'] as const;
const mode = POLICY_MODES.includes(candidate as any) ? candidate : 'observe';
await runPolicyCli(['policy', 'init', '--mode', mode]);

Type guard

function isPolicyMode(v: unknown): v is 'legacy' | 'observe' | 'enforce' {
  return v === 'legacy' || v === 'observe' || v === 'enforce';
}

Prevention

When it happens

Trigger: Passing --mode strict, --mode enforcement, --mode Enforce (case-sensitive check), or accidentally supplying a second positional (args[1] is also interpreted as the mode: `ruflo policy init production`).

Common situations: Assuming stricter-sounding mode names exist; capitalization drift; passing a project name as a positional that gets consumed as the mode.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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

Appendix: source

Thrown at v3/@claude-flow/cli/src/commands/policy.ts:55

export const policyCommand: Command = {
  name: 'policy',
  description: 'Agentic policy engine — evaluate actions, manage rules/approvals, and verify the decision ledger (ADR-324)',
  options: [
    { name: 'mode', type: 'string', description: 'Policy mode: legacy | observe | enforce' },
    { name: 'project-root', type: 'string', description: 'Project root containing .claude-flow/policy' },
  ],
  async action(context: CommandContext): Promise<CommandResult> {
    const args = (context as { args?: string[] }).args ?? [];
    const flags = (context as { flags?: Record<string, unknown> }).flags ?? {};
    const root = String(flags.projectRoot ?? process.cwd());
    const operation = args[0] ?? 'status';
    try {
      if (operation === 'init' || operation === 'migrate') {
        if (flags.mode || args[1]) requireInteractiveAdministrator();
        const migration = await autoMigratePolicyStateIfNeeded(root);
        const mode = String(flags.mode ?? args[1] ?? '') as PolicyState['mode'];
        if (mode) {
          if (!['legacy', 'observe', 'enforce'].includes(mode)) throw new Error('mode must be legacy, observe, or enforce');
          await setPolicyMode(mode, root);
        }
        return print({ ...migration, state: loadPolicyState(root) });
      }
      if (operation === 'status') {
        const state = loadPolicyState(root);
        return print({
          version: state.version,
          mode: state.mode,
          migratedFrom: state.migratedFrom,
          rules: state.rules.length,
          budgets: state.budgets.length,
          approvals: state.approvals.length,
          receipts: state.receipts.length,
          ledger: await verifyPolicyLedger(root),
        });
      }
      if (operation === 'evaluate') {

View on GitHub (pinned to fa13ee4ad6)