jq Footguns¶
Mistakes that produce wrong data, break pipelines, or silently discard information.
1. Forgetting -r for raw output in scripts¶
You assign NAME=$(echo '{"name":"web"}' | jq '.name'). The variable contains "web" with quotes. Your downstream command receives a literal double-quote character. ssh "web" fails. curl sends quoted strings in headers.
Fix: Always use jq -r (raw output) when feeding jq output into shell variables or other commands. -r strips the JSON string quotes.
2. Not handling null values¶
You run jq '.items[].metadata.annotations.version' but some pods have no annotations. jq outputs null for each missing field. Your script processes the literal string null as if it were a valid version number.
Fix: Use the alternative operator: jq '.metadata.annotations.version // "unknown"'. Or filter nulls: jq 'select(.version != null)'. Always consider what happens when a field is missing.
3. Using .[] on an object when you expected an array¶
You have {"a":1,"b":2} and run .[]. jq iterates over the values (1, 2), losing the keys. You expected [{"a":1},{"b":2}]-style output but got bare values with no context.
Fix: Use to_entries to get key-value pairs: jq 'to_entries[] | {key: .key, value: .value}'. Use keys to see what an object contains before iterating.
4. Forgetting -s (slurp) for multi-line JSON¶
You have a JSONL file (one JSON object per line) and run jq 'length'. It outputs the length of each individual object, not the total count. You wanted to treat the whole file as an array.
Fix: Use jq -s 'length' to slurp all lines into a single array first. Without -s, jq processes each line independently. This distinction matters for sort_by, group_by, min, max, and length.
5. Silently getting no output instead of an error¶
You mistype a field name: jq '.metdata.name' (missing an 'a'). jq does not error — it returns null. Your script continues with empty data, and you spend 20 minutes debugging the wrong thing.
Fix: Use jq -e (exit-status) to make jq return a non-zero exit code when the result is null or false. Combine with set -e in scripts to catch missing fields immediately.
6. String interpolation without parentheses¶
You write jq '"host: .name"' expecting string interpolation. jq outputs the literal string host: .name. You forgot the interpolation syntax.
Fix: Use \() for string interpolation: jq '"host: \(.name)"'. The backslash-paren syntax is jq-specific and easy to forget if you are used to other languages.
7. Modifying JSON without capturing the full object¶
You run jq '.spec.replicas = 5' and pipe it into kubectl apply. But jq only outputs the modified fragment, not the full object. The kubectl apply receives a partial object and fails or overwrites other fields.
Fix: Apply modifications to the full object: jq '.spec.replicas = 5' deployment.json | kubectl apply -f -. Ensure your filter starts from the root (.) and modifies in place rather than extracting and rebuilding.
8. Using jq to parse non-JSON data¶
You pipe kubectl get pods (tabular output) into jq. jq fails with a parse error. You forgot to add -o json to the kubectl command.
Fix: Always ensure your input is actually JSON before piping to jq. Use -o json with kubectl, --output json with AWS CLI, or --format json with other tools. If you are not sure, run the command alone first.
9. Wrong quoting in shell: single vs double quotes¶
You write jq ".items[] | select(.name == \"$VAR\")". The escaping is fragile and breaks with special characters. Or you use single quotes and the shell variable does not expand at all.
Fix: Use --arg to pass shell variables safely: jq --arg name "${VAR}" '.items[] | select(.name == $name)'. This avoids all quoting issues and handles special characters correctly.
10. Not using @csv or @tsv for structured output¶
You build CSV output with string concatenation: jq -r '"\(.name),\(.port)"'. A name field contains a comma. Your CSV is corrupted. Downstream parsers break.
Fix: Use jq -r '[.name, .port] | @csv' for properly escaped CSV output (handles commas, quotes, and newlines in values). Use @tsv for tab-separated output. These built-ins handle edge cases that string concatenation cannot.