The jq Filter That Found the One Different Field

Two payloads looked identical to the eye and differed in one nested field, and the filter diffed them in one line where the visual comparison had taken an…

Share
The jq Filter That Found the One Different Field. Abstract tooling illustration in orange and dark grey on debugly.dev

It ended at the flag. It started at the two responses. Every hand-off in between did exactly what it was told, and this is the one that lied.

The structured diff has a single weak property, and here it is: the tool compares the parsed structures rather than the text, so the ordering, the whitespace and the nesting stop mattering, and the only difference reported is the one that is real.

I have since met the same mechanics in plenty of structured payload.

Why the eye failed

The eye is the text comparison, and the text is the long, and the long is the scroll, and the scroll is the fatigue, and the fatigue is the miss, and the miss is the deep field, and the deep field is the nesting's fifth level, and the fifth level is the invisible, and the invisible is the hour, and the hour is the waste.

The text comparison is also the false positive, and the false positive is the key order, and the key order is the irrelevant, and the irrelevant is the noise, and the noise is the attention's cost, and the cost is the real difference's miss, and the miss is the incident, and the incident is the reason the comparison should be structural rather than textual.

The structural comparison is the parse, and the parse is the tree, and the tree is the walk, and the walk is the every node, and the every node is the exhaustive, and the exhaustive is the no miss, and the no miss is the fix, and the fix is the tool, and the tool is the jq.

The same principle is why the curl command beats the screenshot, which is why the two fixes look alike.

The filters that did the work

The sorted keys output. The jq with the sorted keys is the normalised, and the normalised is the comparable, and the comparable is the diff's input, and the input is the fix, and the fix is the one flag, and the flag is the discipline, because the raw output's key order is the noise.

The path and value listing. The jq with the paths is the flat list, and the flat list is the leaf comparison, and the leaf comparison is the diff, and the diff is the one line's difference, and the difference is the answer, and the answer is the fix, and the fix is the filter, and the filter is the discipline.

The side-by-side field extraction. The jq selecting the two fields is the comparison, and the comparison is the visible, and the visible is the answer, and the answer is the fix, and the fix is the targeted extraction, and the extraction is the faster than the whole diff when the suspect is known.

The array element comparison by key. The jq grouping by the identifier is the aligned, and the aligned is the element-wise, and the element-wise is the real comparison, and the comparison is the fix, and the fix is the sort, because the array order is the noise and the identifier is the identity.

How to build the habit

Save the responses to files. The curl output is the file, and the file is the tool's input, and the input is the comparison, and the comparison is the seconds, and the seconds is the fix, and the fix is the discipline, because the response in the terminal is the scroll and the scroll is the hour.

Normalise before comparing. The sorted keys and the stripped metadata are the comparable, and the comparable is the real difference, and the real difference is the answer, and the answer is the fix, and the fix is the preparation, and the preparation is the discipline, because the timestamps and the request identifiers are the noise.

Diff the smallest meaningful subtree. The subtree is the fast, and the fast is the readable, and the readable is the answer, and the answer is the fix, and the fix is the path, and the path is the discipline, because the whole document diff is the noise when the suspect is known.

Turn the finding into the test. The difference is the assertion, and the assertion is the regression guard, and the guard is the prevention, and the prevention is the fix, and the fix is the test, and the test is the tool's second life, and the life is the value.

Pipe the tool into the existing workflow. The curl into the jq into the diff is the one command, and the one command is the reproducible, and the reproducible is the shareable, and the shareable is the ticket's content, and the content is the next person's start, and the start is the saved hour, which is the whole point, because the diagnosis that lives in one person's terminal is the diagnosis nobody else can repeat.

What I now do

Comparing two JSON payloads by eye compares text rather than structure, so key order, whitespace and nesting depth hide the real difference. Normalise with sorted keys, list the leaf paths and values, align arrays by their identifier, and diff the smallest meaningful subtree.

Two API responses looked identical and differed in one boolean four levels deep, and an hour of scrolling found nothing while one jq filter listed the leaf paths and showed the single mismatched value. Name that one property in review and this class of bug gets hard to ship.


Published on debugly.dev by Rohit Bhadani | Founder of Krova Cloud