nanocoai/nanoclaw · error · Error

${flag} must be valid JSON

Error message

${flag} must be valid JSON

What it means

A flag declared with `type: 'json'` must parse as JSON when passed as a string. JSON.parse threw, and the error is re-thrown with the parse failure as `cause` so the exact syntax problem is preserved.

Source

Thrown at src/cli/crud.ts:439

    switch (def.type) {
      case 'number': {
        const n = Number(v);
        if (Number.isNaN(n)) throw new Error(`${flag} must be a number, got "${v}"`);
        out[def.name] = n;
        break;
      }
      case 'boolean': {
        if (v === true || v === 'true' || v === '1') out[def.name] = true;
        else if (v === false || v === 'false' || v === '0') out[def.name] = false;
        else throw new Error(`${flag} must be true or false, got "${v}"`);
        break;
      }
      case 'json': {
        if (typeof v === 'string') {
          try {
            out[def.name] = JSON.parse(v);
          } catch (err) {
            throw new Error(`${flag} must be valid JSON`, { cause: err });
          }
        }
        break;
      }
      case 'string':
        out[def.name] = String(v);
        break;
    }
    if (def.enum && !def.enum.includes(String(out[def.name]))) {
      throw new Error(`${flag} must be one of: ${def.enum.join(', ')}`);
    }
  }
  return out;
}

// ---------------------------------------------------------------------------
// registerResource
// ---------------------------------------------------------------------------

View on GitHub (pinned to 294ef2aee8)

Solutions

  1. Wrap the JSON in single quotes so the shell passes it verbatim: `--payload '{"key": 1}'`
  2. Validate the payload with `echo '<json>' | jq .` before running the command
  3. Use the `--flag=value` form to avoid tokenization issues
  4. Inspect `error.cause` for the precise JSON.parse position

Example fix

# before
ncl groups config update --id g1 --mounts {/data:/data}
# Error: --mounts must be valid JSON

# after
ncl groups config update --id g1 --mounts '{"/data":"/data"}'
Defensive patterns

Strategy: validation

Validate before calling

if (typeof v === 'string') { try { JSON.parse(v); } catch { throw new Error('payload is not valid JSON — check quoting'); } }

Type guard

function isValidJsonString(v: string): boolean {
  try { JSON.parse(v); return true; } catch { return false; }
}

Try / catch

catch (e) { if (e instanceof Error && /must be valid JSON/.test(e.message)) { /* inspect e.cause for parse position, fix quoting */ } else throw e; }

Prevention

When it happens

Trigger: Passing unquoted or shell-mangled JSON (`--config {a:1}` — unquoted keys are invalid JSON); single-quote wrapping stripped by the shell leaving bare braces that trigger globbing or splitting; trailing commas; passing a filename instead of file contents; passing YAML instead of JSON.

Common situations: Shell quoting mistakes with nested quotes (`--payload "{\"k\":1}"` done wrong); agents emitting pretty-printed multi-line JSON the shell splits on spaces; forgetting that JSON requires double-quoted strings.

Related errors


AI-assisted analysis of nanocoai/nanoclaw@294ef2aee8 (2026-08-28). Data as JSON: /api/errors/341abb505e3da984. Report an issue: GitHub.