ruvnet/ruflo · error · Error

revoke requires an approval id

Error message

revoke requires an approval id

What it means

Thrown by the revoke branch when args[1] (the approval identifier) is missing. Unlike approve, revoke is supported interactively, but it still needs the target approval id so the ledger records exactly which approval was withdrawn.

Source

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

        const rule = argJson<PolicyRule>(args[2], 'rule add');
        await upsertPolicyRule(rule, root);
        return print({ success: true, ruleId: rule.id });
      }
      if (operation === 'budget' && args[1] === 'set') {
        requireInteractiveAdministrator();
        const budget = argJson<BudgetLimit>(args[2], 'budget set');
        await setPolicyBudget(budget, root);
        return print({ success: true, budgetId: budget.id });
      }
      if (operation === 'approve') {
        throw new Error(
          'approval issuance requires an authenticated human identity adapter; '
          + 'the local TTY is not an identity credential',
        );
      }
      if (operation === 'revoke') {
        requireInteractiveAdministrator();
        if (!args[1]) throw new Error('revoke requires an approval id');
        return print({ success: await revokePolicyApproval(args[1], root), approvalId: args[1] });
      }
      if (operation === 'audit') {
        const state = loadPolicyState(root);
        return print({ receipts: state.receipts });
      }
      if (operation === 'verify') return print(await verifyPolicyLedger(root));
      throw new Error(`unknown policy operation: ${operation}`);
    } catch (error) {
      const message = error instanceof Error ? error.message : String(error);
      output.printError(message);
      return { success: false, exitCode: 1, data: { error: message } };
    }
  },
  examples: [
    { command: 'ruflo policy status', description: 'Show policy mode and ledger health' },
    { command: 'ruflo policy init --mode observe', description: 'Migrate an existing install without blocking legacy actions' },
    { command: 'ruflo policy budget set \'{"id":"daily-model","action":"model.call","maxCostUsd":10,"periodMs":86400000}\'', description: 'Set an atomic policy budget ceiling' },

View on GitHub (pinned to 6b01dc5a68)

Solutions

  1. Look up the approval id first: `ruflo policy audit` prints the receipts list.
  2. Pass the id as the positional argument: `ruflo policy revoke <approvalId>`.
  3. Run from an interactive terminal — revoke also calls requireInteractiveAdministrator().

Example fix

// before
ruflo policy revoke
// after
ruflo policy revoke appr_2024_08_12_abc
Defensive patterns

Strategy: validation

Validate before calling

function resolveApprovalId(arg?: string): string {
  if (!arg) throw new Error('revoke requires an approval id');
  return arg;
}
resolveApprovalId(process.argv[3]); // throws before reaching the CLI

Type guard

const isApprovalId = (v: unknown): v is string =>
  typeof v === 'string' && v.trim().length > 0;

Try / catch

try {
  await revokePolicyApproval(id, root);
} catch (e) {
  const msg = e instanceof Error ? e.message : String(e);
  if (msg === 'revoke requires an approval id') {
    const ids = (await auditPolicy()).receipts.map(r => r.id);
    console.error('Pass one of:', ids.join(', '));
    process.exit(2);
  }
  throw e;
}

Prevention

When it happens

Trigger: Running `ruflo policy revoke` with no second positional token, or with the id accidentally placed in a flag the command does not read.

Common situations: Forgetting the id, copy-pasting only the verb, or passing `--id <x>` (a flag) instead of the positional the command expects.

Related errors


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