ruvnet/ruflo · error · Error

revoke requires an approval id

Error message

revoke requires an approval id

What it means

The `policy revoke` subcommand requires the approval id as its first positional argument; when args[1] is missing or empty, this error is thrown before revokePolicyApproval runs. The id identifies which approval entry to remove from the policy state.

Solutions

  1. List approvals first with `ruflo policy audit` and copy the exact approval id
  2. Pass it positionally: ruflo policy revoke <approvalId>
  3. Quote ids that contain special characters so the shell delivers them intact

Example fix

# before
ruflo policy revoke

# after
ruflo policy revoke appr_20260818_001
Defensive patterns

Strategy: validation

Validate before calling

if (!approvalId || approvalId.trim() === '') {
  const audit = await runPolicyCli(['policy', 'audit']); // read receipts to find the id
  throw new Error('approval id required — pick one from `policy audit`');
}
await runPolicyCli(['policy', 'revoke', approvalId]);

Type guard

function hasApprovalId(v: string | undefined): v is string {
  return typeof v === 'string' && v.trim().length > 0;
}

Prevention

When it happens

Trigger: Running `ruflo policy revoke` with no argument, or passing an empty string '' (also falsy), or an invocation where a preceding flag consumed the value.

Common situations: Assuming revoke will prompt for the id; passing the id after another argument that shifts positions; quoting mistakes yielding an empty argv entry.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: 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 fa13ee4ad6)