name: processing-json description: Creates, reads, modifies, validates, and queries JSON and JSON Lines files. Use when the user asks to read, write, parse, edit, update, merge, validate, pretty-print, or query a .json or .jsonl file, mentions JSON data or JSON Lines, or asks to fix invalid JSON. Do not use for YAML/TOML config files or for designing APIs.
Processing JSON
When to use / when NOT to use
- Use for: any task where a
.jsonor.jsonlfile is the input or output — creating, parsing, editing, validating, querying. - Do NOT use for: YAML/TOML config files or API design discussions.
Quick reference — one default per operation
Read / write — Python stdlib json:
python
import json
with open("data.json", encoding="utf-8") as f:
data = json.load(f) # load() IS the syntax validator
with open("data.json", "w", encoding="utf-8") as f:
json.dump(data, f, indent=2, ensure_ascii=False)JSON Lines — one object per line, never json.load the whole file:
python
records = [json.loads(line) for line in open("data.jsonl", encoding="utf-8") if line.strip()]
with open("out.jsonl", "w", encoding="utf-8") as f:
for r in records:
f.write(json.dumps(r, ensure_ascii=False) + "\n")Modify — always atomically (temp file + rename; a crash mid-write can't corrupt the original):
python
import json, os, tempfile
with open("data.json", encoding="utf-8") as f:
data = json.load(f)
data["version"] = 2
fd, tmp = tempfile.mkstemp(dir=os.path.dirname(os.path.abspath("data.json")))
with os.fdopen(fd, "w", encoding="utf-8") as f:
json.dump(data, f, indent=2, ensure_ascii=False)
os.replace(tmp, "data.json")Query — escape hatch for large files: jq '.items[] | select(.active)' big.json (requires jq installed: brew install jq). For everything else, load and filter in Python.
Schema validation: pip install jsonschema, then jsonschema.validate(instance=data, schema=schema).
Rules
- Never edit JSON with regex or string replacement. Parse → mutate → dump. Always.
- Preserve key order: Python dicts keep insertion order; do not pass
sort_keys=Trueunless asked. indent=2, ensure_ascii=Falsefor human-facing files; single-line compact only for machine-to-machine output.
Workflow
- Load the input (
json.load/ line-by-line for.jsonl). A parse error here is a finding, not a failure — see edge cases. - Apply the change/query in Python on the parsed structure.
- Write atomically (recipe above).
- Validate: re-open and
json.loadthe written file; for.jsonl, re-parse every line. Only then report success. - Report the output path and what changed (keys touched, records added/removed).
Edge cases & failure modes
- Malformed JSON →
json.JSONDecodeErrorincludes line and column; report it verbatim (e.g. "Expecting ',' delimiter: line 12 column 3") and show the offending line. Common causes: trailing commas, single quotes, comments — fix precisely, don't guess. NaN/Infinityin input → stdlib accepts them but they are NOT valid JSON; re-emit withjson.dump(..., allow_nan=False)after replacing them withnull(confirm with the user).- Missing dependency → only third-party need:
pip install jsonschema(schema validation) orbrew install jq. - Huge file (>500 MB) → if it's
.jsonl, stream line-by-line; if a single JSON document, usejqrather than loading into Python. - Empty file → report "file is empty — not valid JSON (an empty JSON file should contain
{}or[])" and ask which the user wants. - Duplicate keys →
json.loadsilently keeps the last one; when auditing, parse withobject_pairs_hook=listto detect them.
References
Deeper recipes (merging, diffing, flattening, jsonl↔json, encoding traps): see references/recipes.md.