ruvnet/ruflo · error · Error
must be valid JSON
Error message
${label} must be valid JSON What it means
policy.ts's argJson() throws when the supplied JSON string reaches the CLI but fails JSON.parse. The argument is present; it is just not strict JSON — quoting damage or syntax errors are the usual cause.
Solutions
- Validate the payload first: echo '<payload>' | jq . — jq pinpoints the exact syntax error
- On POSIX shells wrap the JSON in single quotes and use double quotes inside it
- On Windows, escape inner double quotes or build the JSON in a variable via a tool and pass it through
- Remove trailing commas and comments — only strict JSON parses
Example fix
# before
ruflo policy evaluate '{"identity": {"id":"a1",},}'
# after
ruflo policy evaluate '{"identity":{"id":"agent-1","type":"agent"},"action":{"type":"deploy","environment":"production"}}' Defensive patterns
Strategy: validation
Validate before calling
function mustParse<T>(s: string, label: string): T {
try { return JSON.parse(s) as T; }
catch { throw new Error(`${label} is not valid JSON — check quoting/trailing commas`); }
}
const payload = mustParse(rawArg, 'policy payload'); // run before the CLI does Type guard
function isParsableJson(s: string): boolean {
try { JSON.parse(s); return true; } catch { return false; }
} Try / catch
try {
await runPolicyCli(['rule', 'add', raw]);
} catch (err) {
if (err instanceof Error && err.message.includes('must be valid JSON')) {
// re-quote the payload (single-quote outer, double-quote inner) and retry once
} else throw err;
} Prevention
- Pipe payloads through jq before invoking the CLI to prove they parse
- Single-quote outside, double-quote inside on POSIX; on Windows write JSON to a file-based flow or escape carefully
- Never build JSON by string concatenation of user input
When it happens
Trigger: JSON containing single quotes inside a single-quoted shell string, trailing commas, unquoted keys, smart quotes from pasting, or an unquoted JSON string that the shell split into multiple argv entries (so JSON.parse sees only a fragment like '{id:').
Common situations: Windows cmd/PowerShell where single quotes don't group arguments; hand-typing JSON at the prompt; JSON produced by echo with variable interpolation inserting stray characters.
Understand the failure class
Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.
Related errors
- requires a JSON argument
- approval issuance requires an authenticated human identity…
- mode must be legacy, observe, or enforce
- policy administration requires an interactive local terminal
- revoke requires an approval id
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/0b16563932887fa6.
Report an issue: GitHub.
Appendix: 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 fa13ee4ad6)