The most reliable way to avoid JSON Diff mistakes is to treat the tool as a structural change inspector, not a text editor, a patch engine, or a move detector. JSON Diff compares two strict JSON values as parsed data rather than as formatted bytes, and reports added, removed, changed, and type-changed entries at RFC 6901 JSON Pointer paths, so nearly every mistake readers make comes from importing expectations borrowed from a different category of tool. The tool deliberately ignores whitespace and object member order, because real JSON objects are unordered collections per RFC 8259, and it deliberately reports arrays positionally without inventing item identities. That single design choice rules out half of the false-positive complaints users hit on first contact: changing key order on one side does not produce phantom diffs, while moving an item from index 2 to index 5 does produce several diffs. Add in strict parsing rules (no comments, no trailing commas, no undefined or NaN), the JSON Pointer escape rules from RFC 6901, and JavaScript Number precision for every numeric input, and the mistake surface gets wide enough to deserve a checklist before you paste a large payload in.

Why JSON Diff Mistakes Come From Category Confusion
Most JSON Diff mistakes come from applying expectations borrowed from a different category of tool. If you have used a line-based text diff for years, your first instinct on seeing two JSON documents is to compare them character by character, looking at indentation, brace placement, and trailing commas. That instinct produces false positives immediately, because RFC 8259 makes whitespace insignificant between tokens and explicitly defines objects as unordered collections of members.
JSON Diff, by contrast, parses both sides with a strict RFC 8259 parser before any comparison happens, so indentation, line breaks, and object member order are normalized away before the first added or removed entry is computed. A reader who pastes the same document with reordered keys on each side will see an empty change list, and the right reaction is relief, not surprise. The tool will not flag formatting drift as a semantic difference, which means any change that does appear is a real value, key, type, or array-position change worth investigating.
Three other categories of confusion show up just as often. Readers expect JSON Patch output (RFC 6902 operations) when what they receive is a review-oriented change list. Readers expect array reordering to be summarized as a single move, when the comparison is strictly positional. Readers expect arbitrary-precision integer math, when the parser uses JavaScript's IEEE 754 Number type and rounds some inputs before comparison. Knowing which category you are actually in is the prerequisite for every other section in this guide.
Treating the Change List as an Executable Patch
The single most expensive mistake readers make with JSON Diff is treating the copied output as RFC 6902 JSON Patch and applying it to the source document. The output is not JSON Patch, not JSON Merge Patch, not a unified text diff, and not a schema migration. It is a product-defined change list that records each added, removed, changed, and type-changed entry with its RFC 6901 JSON Pointer path and the before-and-after values.
The structural difference matters. JSON Patch includes add, remove, replace, move, copy, and test operations with application semantics, while the JSON Diff change list contains no operations at all — only observations. The tool never claims that a removed value can be restored after surrounding changes, never emits move or copy, and never tests a precondition. If you paste the change list into a JSON Patch library expecting it to replay, the library will reject every entry.
The safe workflow is to use the change list for review and pull requests, then reach for a maintained patch implementation and application-specific tests before any change is applied automatically. Review the entries yourself, map each path to the operation your application actually needs, and verify the resulting document round-trips through your parser before you trust it.
Misreading RFC 6901 Path Escaping
JSON Pointer paths look like file paths, but the escaping rules catch readers who have never read RFC 6901. Two characters have special meaning inside a reference token: the slash / separates tokens, and the tilde ~ introduces an escape sequence. Member names that contain either character must be encoded, otherwise a path like /first/name silently refers to the children first and name rather than the member named first/name.
The escaping is exact and asymmetric. A literal slash inside a member name becomes ~1, and a literal tilde becomes ~0. Order matters: ~1 must be applied after ~0 to avoid double-encoding. Array positions use plain decimal tokens such as /0, /1, /12, and the root of the document is the empty string, displayed as root in the human-readable list rather than as a leading slash.
A reader who copies a path like /settings/ui~1theme and assumes it refers to a child called ui/theme will read the wrong member. The corrected path is /settings/ui~1theme — the ~1 in the middle of a token is a real escape sequence, not a separator. When you paste these paths back into your own code, decode ~1 to / and ~0 to ~ in that order before treating the result as a member name.
| Character in member name | Encoded token |
|---|---|
| / (forward slash) | ~1 |
| ~ (tilde) | ~0 |
| Plain alphanumeric or underscore | Unchanged |
Misreading Array Reordering as a Move
JSON Diff compares arrays positionally and reports no more, no less. Arrays are ordered sequences in JSON, and the comparison walks index 0 against index 0, index 1 against index 1, and so on. The tool does not guess identity keys, does not compute a longest common subsequence, and does not treat arrays as sets, because those policies depend on the data contract and can hide meaningful ordering changes.
The practical consequence is that moving an item from index 2 to index 5 shows up as a chain of changes rather than one neat move. The item at the old index will be reported as removed, a new entry will appear at the new index with its right value, and any indexes between will be flagged as changed because their contents no longer match positionally. A reviewer who expects a single diff line for a reordering will misread the magnitude of the change.
If your application treats array order as semantically meaningless, normalize both sides to a canonical order before pasting. If your application treats array order as meaningful, read the positional chain literally and review whether the new order is what was actually intended.
Number Precision and Numeric Edge Cases
All numeric inputs go through JavaScript's IEEE 754 Number type before any comparison, and that choice has three consequences readers should anticipate.
First, integers beyond the safe-integer limit may already be rounded when the parser hands them to the comparison. The safe-integer limit is defined as 2^n − 1 where n is the number of significand bits, and JavaScript defines n = 53. Substituting, the limit equals 2^53 − 1 = 9007199254740991. Any integer whose absolute value exceeds 9007199254740991 is not guaranteed to round-trip through the comparison, so two large integer strings that differ only past the sixteenth significant digit can produce an incorrect "no change" result.
Second, fine decimal distinctions are not preserved. Values such as 0.1 + 0.2 = 0.30000000000000004 already exist in the parsed representation, so an after-value that is mathematically equal but textually distinct may or may not match depending on which exact bytes the parser produced. If you need exact decimal behavior, compare the source with a parser and numeric model designed for that contract.
Third, positive zero and negative zero compare as the same JSON numeric value, because -0 === 0 is true in JavaScript. A reader who expects a sign difference to be reported will be surprised by an empty change list. For financial or signed-magnitude work, compare the source representation directly rather than relying on browser arithmetic.
How to Diff JSON Without the Common Pitfalls
This is the workflow that avoids every mistake covered above.
- Validate both sides with a strict RFC 8259 parser before pasting. Comments, trailing commas, undefined, NaN, Infinity, BigInt syntax, and JavaScript object literals are rejected by JSON Diff, and a side that fails to parse produces no comparison at all.
- Normalize your expectations, not your data. Decide whether object key order matters in your contract (it almost never does), whether array order matters (usually yes), and whether the precision of JavaScript Numbers is acceptable for the values in question.
- Paste the left and right documents into JSON Diff — formatting and object member order may differ, and the tool will treat them equivalently.
- Run the comparison and inspect each added, removed, changed, or type-changed entry by its RFC 6901 JSON Pointer path. Verify that the path decodes correctly, paying special attention to ~1 for / and ~0 for ~.
- For array reordering, count the entries. A chain of remove + add + multiple changes is positional reporting, not a bug, and indicates a real reordering rather than a logical move.
- Copy the change list for review. Do not paste it into a JSON Patch library expecting RFC 6902 semantics; the output is a review-oriented change list with before and after values only.
- Before any change is applied automatically, build a dedicated patch implementation and tests for your data contract. Apply the tests to a snapshot of the production document and verify the round-trip.
- Review any sensitive before-and-after values before copying the change list into logs, tickets, or chat threads. The tool runs locally, but the review trail may not.
Inputs the Tool Refuses: What to Do Instead
JSON Diff is strict on purpose, and several common JSON-ish inputs are rejected rather than silently coerced. Comments of any style, trailing commas, the JavaScript literal undefined, the IEEE special values NaN and Infinity, BigInt syntax with the n suffix, and bare JavaScript object literals that omit quotes around keys all fail strict RFC 8259 parsing. The right response is to remove the offending syntax with a real JSON parser, then paste the cleaned result.
Duplicate member names in the source text are also unaddressable by the tool, because normal JSON parsing collapses duplicates into a single entry before the comparison sees the object. If your data has duplicate keys and the duplicates are meaningful, you need a non-standard parser that preserves them, then a hand-written diff on the resulting structure.
Each input is bounded at 500,000 characters, nesting to 50 comparison levels, and the output is bounded at 5,000 changes. The tool fails rather than truncating a larger result, which protects you from a silent partial answer that looks complete. If your documents exceed those limits, split the comparison by a known partition key or use a streaming differ designed for the volume.
Quick Reference: Change Types
| Change type | Trigger | What the entry contains |
|---|---|---|
| added | Key appears only on the right, or array position exists only on the right | RFC 6901 path and the right value |
| removed | Key appears only on the left, or array position exists only on the left | RFC 6901 path and the left value |
| changed | Same path, same JSON type, different value | RFC 6901 path, left value, and right value |
| type-changed | Same path, different JSON type (for example number to string, object to array, or null to boolean) | RFC 6901 path, left value, and right value |
Each entry is reported against an RFC 6901 JSON Pointer, and object member names are sorted for deterministic reporting, so two runs over the same pair of documents will produce the same change list in the same order. Subtrees can appear as values when a whole member is added, removed, or changes type, which keeps the output readable even when the structural difference is large. The eight external fixtures the tool is verified against — changed, added, removed, type-changed, array index, slash escaping, tilde escaping, and object-order equality — give a fixed regression surface you can also test against your own expectations before trusting a result in production.
Related reading: How to Format JSON in Sublime Text: Plugins and Beyond.
Related reading: JSON to CSV Cheat Sheet: Rules, Limits, and a Quick Workflow.