Why Malformed JSON?
LLMs frequently generate invalid JSON in their tool call arguments. This happens because language models work with tokens, not syntax validation:| Problem | Example | Frequency |
|---|---|---|
| Single quotes instead of double | {'cmd': 'read'} | Very common |
| Unquoted keys | {cmd: "read", file: "main.go"} | Common |
| Trailing commas | {"cmd":"read","file":"main.go",} | Common |
| Raw value without object | main.go instead of {"file":"main.go"} | Frequent |
| Mixed styles | {cmd: 'read', "file": main.go} | Occasional |
| CLI text instead of JSON | read --file main.go | Frequent |
| JS object literals | {cmd: read, file: main.go} | Occasional |
The 7 Recovery Strategies
TheNormalizeToolArgs system applies up to 7 strategies in sequence, stopping at the first one that produces valid JSON:
1. Standard JSON Parse
1. Standard JSON Parse
Attempts direct parsing with
json.Unmarshal. If the JSON is already valid, it returns immediately without modifications.2. Single Quotes to Double Quotes
2. Single Quotes to Double Quotes
Converts single quotes to double quotes with proper escape handling. Preserves single quotes inside strings and escapes internal double quotes.
3. Unquoted Keys
3. Unquoted Keys
Adds double quotes to keys that are not quoted. Uses regex to detect the
{key: or , key: pattern.4. Combined: Quotes + Keys
4. Combined: Quotes + Keys
Applies the single quote fix first, then the unquoted keys fix. Resolves cases where both problems coexist.
5. Trailing Commas
5. Trailing Commas
Removes commas before
} or ] that make the JSON invalid.6. Plain String Wrapping
6. Plain String Wrapping
When the model sends only a raw value instead of a JSON object, the system wraps it in the correct field based on the tool name.The mapping covers 30+ tools and aliases, including native functions (
read_file, write_file) and coder subcommands (read, exec, search).7. Aggressive Object Literal Fix
7. Aggressive Object Literal Fix
For object literals with no quotes at all, the system manually parses Values are interpreted intelligently:
key: value pairs and rebuilds valid JSON.true/false-> booleans- Numbers -> JSON numbers
null/none-> null- Quoted strings -> strings (quotes removed)
- Everything else -> string
Tool-to-Field Mapping
Plain string wrapping uses an extensive mapping of tool names to their primary input field:- Native Tools
- Coder Subcommands
- Generic Aliases
| Tool | Field | Example |
|---|---|---|
read_file | file | main.go -> {"file":"main.go"} |
write_file | file | output.txt -> {"file":"output.txt"} |
list_directory | dir | ./src -> {"dir":"./src"} |
search_files | term | TODO -> {"term":"TODO"} |
run_command | cmd | go build -> {"cmd":"go build"} |
run_tests | dir | ./pkg -> {"dir":"./pkg"} |
Wrapping is only applied when the value does not look like CLI arguments (no
--flags) and does not start with { or [. This avoids conflicts with the existing CLI argument parser.Unicode Quote Normalization
In addition to JSON recovery, ChatCLI normalizes curly (Unicode) quotes to straight (ASCII) quotes automatically. LLMs frequently generate typographic quotes that cause compilation errors:| Character | Unicode | Replacement |
|---|---|---|
' ' | U+2018, U+2019 | ' (straight single quote) |
" " | U+201C, U+201D | " (straight double quote) |
' | U+2032 (prime) | ' |
" | U+2033 (double prime) | " |
<< >> | U+00AB, U+00BB | << >> |
Configuration
The recovery system works automatically without configuration. All strategies are applied in order until one produces valid JSON.| Variable | Description | Default |
|---|---|---|
| (none) | JSON recovery has no dedicated environment variables | Always active |
The recovery strategies are non-destructive: if none produces valid JSON, the original text is passed through so the CLI parser can attempt to interpret it as positional arguments.
Next Steps
Plugin @coder
Complete reference for the tools that use JSON recovery.
Native Tool Use
With native tool use, JSON comes validated by the API — less need for recovery.
Tool Result Management
How tool results are managed after execution.
Coder Mode
The complete engineering workflow with tool calls.