← Back to blog

Fix 3 Common Patch Failures: JSON Patch vs Merge Patch for Developers

October 9, 2026
Fix 3 Common Patch Failures: JSON Patch vs Merge Patch for Developers

JSON Patch (RFC 6902) is an operation-based format for precise edits. JSON Merge Patch (RFC 7396) is a simpler partial-document merge. Use Patch when you need arrays, conditional edits, or exact control. Use Merge Patch for simple object updates where hand-written requests are common. The two also carry different media types: application/json-patch+json and application/merge-patch+json.


TL;DR:

  • Choose JSON Patch when arrays need partial edits or concurrent clients need conditional writes; its test operation checks values before changes.
  • Merge Patch suits requests written by hand for simple object updates, but it replaces whole arrays and interprets null as deleting a key.
  • Treat JSON Patch as atomic: one failed operation rejects the entire request, with 400 for malformed syntax and 409 or 412 for failed tests.
  • Validate pointer paths against current data, check the final document against its schema, and require the endpoint’s documented media type rather than guessing.

Datatool
Catch Broken Structured Data
Check malformed structured data with Datatool, a developer-focused platform for repairing, validating, and testing AI-generated output.
Explore Datatool

Table of Contents

What is JSON Patch and how does it work?

JSON Patch defines a list of operations applied in order to a target document. Each operation is explicit about what it does and where. The format recognizes six operations, and the RFC 6902 specification states a patch document is an array of operation objects applied sequentially and atomically.

  • add: inserts a value at a target location.
  • remove: deletes the value at a target location.
  • replace: swaps the value at a target location for a new one.
  • move: relocates a value from one path to another.
  • copy: duplicates a value from one path to another.
  • test: checks that a value matches an expectation before continuing.

The test op matters more than it looks. It lets you verify a value before mutating anything, which guards against lost updates when two clients edit the same resource. A request sends the operations with Content-Type: application/json-patch+json.

Patches apply sequentially and atomically: if any operation fails, the whole patch fails according to guidelines explained in The JSONL Format: A Practical Guide for Developers. A test that doesn't match, a remove targeting a path that doesn't exist, or a malformed pointer should all cause the server to reject the entire request rather than applying part of it. Typical server error responses include:

  • 400 Bad Request for malformed patch syntax or invalid JSON Pointer paths.
  • 409 Conflict or 412 Precondition Failed when a test operation fails.
  • 422 Unprocessable Entity when the patch is well-formed but produces an invalid document.

What is JSON Merge Patch and how does it differ?

JSON Merge Patch skips operations entirely. You send a partial document, and the server merges it into the existing resource. The RFC 7396 specification defines this with a recursive merge rule: when the patch is an object, each key merges into the target object; when the patch is not an object, it replaces the target outright.

This is where Merge Patch gets a reputation for being easy to misuse. A null value in the patch means "delete this key," not "set this key to null." There's no way to express "set to null" and "remove the key" as two different intentions in the same format. If your application logic needs that distinction, Merge Patch can't give it to you.

Merge Patch null removes an object property

A request uses Content-Type: application/merge-patch+json. Consider a user record:

{"name": "Jess Rivera", "role": "admin", "phone": "555-0199"}

Sending this merge patch:

{"role": "editor", "phone": null}
  • Updates role to "editor".
  • Deletes the phone key entirely, because null triggers removal under RFC 7396.
  • Leaves name untouched since it's absent from the patch.

JSON Patch vs Merge Patch: a side-by-side comparison

AxisJSON Patch (RFC 6902)JSON Merge Patch (RFC 7396)
Format modelOrdered list of operationsPartial document merged by example
Media typeapplication/json-patch+jsonapplication/merge-patch+json
Array handlingExplicit index-based add/remove/moveEntire array replaced, no partial edit
Conditional opstest operation supportedNot supported
Hand-edit friendlinessVerbose, harder to write by handReads like the object itself, easy to write
Typical use casesArray mutations, concurrency checks, precise diffsSimple field updates, config patches, small CRUD APIs

The trade-off is verbosity against precision. Merge Patch payloads are shorter and map closely to how developers already think about objects, according to a comparison from Zuplo's learning center. JSON Patch payloads cost more bytes and more code to generate, but they let you describe exactly what changed, which matters once you have arrays or concurrent writers.

The most common defects we see show up in three places: wrong pointer paths, confusing null with delete, and off-by-one array indices. Test your patch logic against these three before shipping a PATCH endpoint.

How to choose a format and fix a broken patch

Run through this checklist before picking a format:

  1. Does the resource include arrays that need partial edits? Choose JSON Patch.
  2. Do you need conditional writes to avoid lost updates? Choose JSON Patch and use test.
  3. Are clients writing patches by hand or from simple forms? Merge Patch is easier to generate correctly.
  4. Is payload size a concern for high-volume clients? Merge Patch is typically smaller for flat objects.
  5. Does your team need to express "set to null" distinctly from "delete"? JSON Patch, since Merge Patch can't separate the two.
  6. What do your client libraries already support? Confirm before committing to either format.

Here's a failure we've seen repeatedly: a client wants to set a discount field to null to mean "no discount applies right now," but intends to keep the field in the record for future use. Using Merge Patch:

PATCH /orders/42
Content-Type: application/merge-patch+json

{"discount": null}

This deletes the discount key entirely, per RFC 7396's merge rules. If downstream code expects the key to exist and checks order.discount === null, it now breaks on a missing property instead.

The fix is JSON Patch with an explicit replace:

PATCH /orders/42
Content-Type: application/json-patch+json

[{"op": "replace", "path": "/discount", "value": null}]

A quick assertion to confirm the fix:

const res = await fetch("/orders/42", {
  method: "PATCH",
  headers: { "Content-Type": "application/json-patch+json" },
  body: JSON.stringify([{ op: "replace", path: "/discount", value: null }])
});
const order = await res.json();
console.assert(order.discount === null, "discount should be null, not missing");
console.assert(res.status === 200, "expected 200 on successful patch");

Return 400 for malformed patch syntax and 409 or 412 when a test operation fails, so clients can tell a syntax problem from a concurrency conflict.

Pro Tip: Log the raw patch payload on every PATCH failure. Half the "random" bugs in patch handling turn out to be a wrong Content-Type header, not a logic error.

What datatool.dev testing reveals about broken patches

Testing of patch payloads against malformed and AI-generated JSON reveals three common failures: a missing or wrong Content-Type header, a JSON Pointer path that targets a key that doesn't exist, and partial objects from AI outputs that look valid but drop required fields mid-patch.

Before deploying a PATCH endpoint, run these checks locally:

  • Validate pointer paths against a current snapshot of the target document, not a stale schema.
  • Reject patches where null appears in Merge Patch bodies without confirming deletion is the intended behavior.
  • Run malformed and partial payloads through a JSON repair tool before they reach your patch logic, especially when the source is an LLM.

Our JSON input validation guide covers the parsing and validation steps that catch most of these before they hit production.

Pragmatic rules for PATCH behavior in APIs

In our view, Merge Patch should be the default for simple object updates, and JSON Patch should be reserved for arrays or conditional writes. Document which format your endpoint expects in the OpenAPI spec and reject the wrong Content-Type outright instead of guessing. The null-as-delete behavior in Merge Patch trips up more integrations than any other part of either spec, so say it plainly in your docs, not as a footnote.

— Gregory

FAQ

What are the differences between JSON Patch and JSON Merge Patch?

JSON Patch uses a list of explicit operations like add, remove, and replace, while JSON Merge Patch sends a partial document that gets merged into the target. Patch supports array edits and conditional checks through the test operation; Merge Patch replaces arrays wholesale and treats null as a delete instruction, per RFC 7396.

Is PATCH faster than PUT?

PATCH payloads are usually smaller than PUT because you send only the changed fields or operations instead of the full resource. Speed also depends on server-side merge or operation processing, so the gain is mainly in bandwidth, not guaranteed latency.

What is a JSON Patch?

A JSON Patch is an array of operation objects, each one an add, remove, replace, move, copy, or test, applied in order to a JSON document. The format is defined in RFC 6902 and sent with the application/json-patch+json media type.

Should I use PATCH or PUT?

Use PATCH when you want to update part of a resource without resending the whole thing, and PUT when you're replacing the entire resource. PATCH requires picking a format, JSON Patch or Merge Patch, since the HTTP method itself doesn't define the body structure.

Does JSON Patch work well with JSON Schema validation?

JSON Patch operations target paths using JSON Pointer, so schema validation typically runs against the resulting document after the patch applies, not against the patch itself. Validate the final merged or patched document against your schema before persisting it, since a patch that applies cleanly can still produce an invalid object.

Sources