Skip to main content
← Back to list
01Issue
BugShippedSwamp CLIPublic
Assigneeszack

Relationships

#3286 Record-typed arguments are not JSON-parsed from plain key=value, unlike array and object arguments

Opened by zack · 10/12/2026· Shipped 10/12/2026

Description

A record-typed argument (z.record(...)) given as plain key=<JSON object> on the command line is never JSON-parsed. Array-typed and object-typed arguments given the same way are parsed, so the behaviour is inconsistent, and the resulting errors are misleading.

Found while triaging swamp-club#3275, which reported the sensitive-record symptom below as a limitation of the sensitive-argument guard. The guard is behaving correctly; the value reaches it as one raw string.

Steps to reproduce

Extension model with:

globalArguments: z.object({
  tokens: z.record(z.string(), z.string()).meta({ sensitive: true }).optional(),
}),
  1. swamp model create <type> demo with a --global-arg whose key is tokens and whose value is a JSON object holding one plain string
    • Actual: Invalid global arguments for type '...': tokens: Invalid input: expected record, received string
  2. The same command where the JSON object's only value is a vault.get expression
    • Actual: refused with Global argument 'tokens' is marked sensitive and cannot be set to a literal value ..., although every value in the map is a vault expression.
  3. The same data supplied as --global-arg 'tokens.a=<vault expression>' or --global-arg 'tokens:json=<JSON object>' is accepted and stores a real map.

For comparison, --global-arg 'users=[ ... ]' for a z.array(...) field and --global-arg 'nested={ ... }' for a z.object(...) field are both parsed from the plain form.

Cause

parseKeyValueInputs (src/cli/input_parser.ts) only JSON-parses a value when the key carries the :json suffix. coerceMethodArgs (src/domain/models/zod_type_coercion.ts) then JSON-parses string values for fields whose schema type is array or object, but has no branch for record. A record field therefore stays a string: with a literal inside it fails schema validation, and with an expression inside it is a string mixing literal text with an expression, which the sensitive guard rightly treats as a literal.

Expected

A string value for a record-typed field is JSON-parsed when it holds a JSON object, the same as an object-typed field, so the plain key=<JSON object> form works for records and the sensitive guard evaluates the map's values individually.

Environment

  • swamp 20261012.132734.0-sha.39452c84
  • Reproduction repo: /tmp/swamp-repro-issue-3275 (cases D and E)
02Bog Flow
✓OPEN✓TRIAGED✓IN PROGRESS✓SHIPPED+ 1 MOREASSIGNED+ 2 MOREREVIEW+ 7 MOREPR_MERGED+ 2 MORESESSION_SUMMARIZED

Shipped

10/12/2026, 2:56:42 PM

Click a lifecycle step above to view its details.

03Sludge Pulse
zack assigned zack10/12/2026, 2:38:55 PM

Sign in to post a ripple.