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
- Use exactly one of legacy, observe, or enforce, all lowercase
- Check `ruflo policy status` to see the current mode and vocabulary
- 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
- Type mode fields as the literal union 'legacy' | 'observe' | 'enforce' in your config
- Lowercase and trim user-supplied modes before passing them on
- Never pass a free-form second positional to `policy init` — it is parsed as the mode
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
- approval issuance requires an authenticated human identity…
- invalid-approval
- invalid-budget-limit
- invalid-budget-period
- Invalid completion type
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)