ruvnet/ruflo · error · Error

${label} requires a JSON argument

Error message

${label} requires a JSON argument

What it means

Thrown by the argJson() helper in the Ruflo policy CLI command when a JSON-valued argument is entirely absent (undefined or empty string). The helper refuses to coerce a missing argument to a default object because policy rules and budgets are security-sensitive — silently substituting {} could write a no-op rule. It is a usage error, not a runtime fault.

Source

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

  PolicyRequest,
  PolicyRule,
  PolicyState,
} from '@claude-flow/security';
import type { Command, CommandContext, CommandResult } from '../types.js';
import { output } from '../output.js';
import {
  autoMigratePolicyStateIfNeeded,
  evaluatePolicyRequest,
  loadPolicyState,
  revokePolicyApproval,
  setPolicyBudget,
  setPolicyMode,
  upsertPolicyRule,
  verifyPolicyLedger,
} from '../services/policy-runtime.js';

function argJson<T>(value: string | undefined, label: string): T {
  if (!value) throw new Error(`${label} requires a JSON argument`);
  try { return JSON.parse(value) as T; }
  catch { throw new Error(`${label} must be valid JSON`); }
}

function print(data: unknown): CommandResult {
  output.writeln(JSON.stringify(data, null, 2));
  return { success: true, exitCode: 0, data };
}

function requireInteractiveAdministrator(): void {
  if (!process.stdin.isTTY || !process.stdout.isTTY) {
    throw new Error('policy administration requires an interactive local terminal');
  }
}

export const policyCommand: Command = {
  name: 'policy',
  description: 'Agentic policy engine — evaluate actions, manage rules/approvals, and verify the decision ledger (ADR-324)',

View on GitHub (pinned to 6b01dc5a68)

Solutions

  1. Append a valid JSON object as the next positional argument: `ruflo policy budget set '{"id":"daily","action":"model.call","maxCostUsd":10,"periodMs":86400000}'`.
  2. If building the call from a shell variable, ensure it is non-empty and properly single-quoted so the shell does not strip it.
  3. Check the operation's argument order against the examples block at the bottom of policy.ts (rule add takes args[2], budget set takes args[2]).

Example fix

// before
ruflo policy budget set
// after
ruflo policy budget set '{"id":"daily","action":"model.call","maxCostUsd":10,"periodMs":86400000}'
Defensive patterns

Strategy: validation

Validate before calling

function buildPolicyArgs(op: string, json?: string): string[] {
  if ((op === 'rule' || op === 'budget') && !json) {
    throw new Error(`operation '${op}' requires a non-empty JSON argument`);
  }
  return json === undefined ? [op] : [op, json];
}
// before invoking the policy command:
buildPolicyArgs('budget', process.env.POLICY_JSON); // throws early if missing

Type guard

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

Try / catch

try {
  await runPolicyCommand(argv);
} catch (e) {
  const msg = e instanceof Error ? e.message : String(e);
  if (msg.endsWith('requires a JSON argument')) {
    console.error('Usage: ruflo policy <rule|budget|evaluate> \'<json>\'');
    process.exit(2);
  }
  throw e;
}

Prevention

When it happens

Trigger: Running `ruflo policy rule add`, `budget set`, or `evaluate` without the trailing JSON positional argument (e.g. `ruflo policy rule add` with no third token, or `policy budget set` with args[2] unset). argJson(value, label) is called with value === undefined.

Common situations: Forgetting the JSON blob in a script, quoting that swallows the argument, passing the JSON via a flag the command does not read, or copy-pasting an example that drops the trailing quoted object.

Related errors


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