ruvnet/ruflo · error · Error
${label} must be valid JSON
Error message
${label} must be valid JSON What it means
Thrown by argJson() when JSON.parse() rejects the supplied string. It signals the argument was present but not well-formed JSON, so the policy engine refuses to interpret it rather than guess at a partial structure. Distinct from error 200, which fires on a missing argument.
Source
Thrown at v3/@claude-flow/cli/src/commands/policy.ts:23
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)',
options: [
{ name: 'mode', type: 'string', description: 'Policy mode: legacy | observe | enforce' },View on GitHub (pinned to 6b01dc5a68)
Solutions
- Validate the string with `echo '<json>' | jq .` before running the command — jq reports the exact parse error.
- Single-quote the whole JSON blob in the shell so internal double quotes survive: `'{"id":"x"}'`.
- Generate the JSON with a tool (jq -c, node -e) and pass its stdout rather than hand-typing.
Example fix
// before
ruflo policy evaluate {identity:{id:"a"}}
// after
ruflo policy evaluate '{"identity":{"id":"agent-1","type":"agent"},"action":{"type":"deploy","environment":"production"}}' Defensive patterns
Strategy: validation
Validate before calling
function safeJsonParse<T>(s: string | undefined, label: string): T {
if (!s) throw new Error(`${label} requires a JSON argument`);
try { return JSON.parse(s) as T; }
catch { throw new Error(`${label} must be valid JSON`); }
}
// pre-check before the CLI call:
safeJsonParse(process.env.POLICY_JSON, 'policy arg'); Type guard
function isJsonString(s: string): boolean {
try { JSON.parse(s); return true; } catch { return false; }
} Try / catch
try {
await runPolicyCommand(argv);
} catch (e) {
const msg = e instanceof Error ? e.message : String(e);
if (msg.endsWith('must be valid JSON')) {
console.error('Argument was not valid JSON. Validate with: echo %s | jq .', arg);
process.exit(2);
}
throw e;
} Prevention
- Lint every JSON argument with `jq .` before the CLI call.
- Single-quote blobs to protect embedded double quotes from the shell.
- Build blobs with jq -c to guarantee valid output.
When it happens
Trigger: Passing an unquoted/incorrectly-quoted object to rule add / budget set / evaluate, e.g. `policy budget set {id:x}` (unquoted braces, bad JSON), trailing commas, single-quoted JSON keys, or a JSON string whose outer quotes the shell consumed.
Common situations: Shell quoting mistakes (double quotes around a JSON body containing double quotes), hand-typing JSON with trailing commas or unquoted keys, or piping a non-JSON value into the positional slot.
Related errors
- ${label} requires a JSON argument
- mode must be legacy, observe, or enforce
- revoke requires an approval id
- unknown policy operation: ${operation}
- ${toolsJson} must contain a JSON array of {name, description
AI-assisted analysis of ruvnet/ruflo@6b01dc5a68 (2026-08-12).
Data as JSON: /api/errors/0b16563932887fa6.
Report an issue: GitHub.