Skip to content

fix: preserve nested arrays in cloneDataFromOriginalDoc#17492

Open
Nahid-NHB wants to merge 1 commit into
payloadcms:3.xfrom
Nahid-NHB:fix/json-field-array-of-arrays-clone-3x
Open

fix: preserve nested arrays in cloneDataFromOriginalDoc#17492
Nahid-NHB wants to merge 1 commit into
payloadcms:3.xfrom
Nahid-NHB:fix/json-field-array-of-arrays-clone-3x

Conversation

@Nahid-NHB

Copy link
Copy Markdown

What?

cloneDataFromOriginalDoc mangles a json field's array-of-arrays value (e.g. [[1, 2], [3, 4]]) into an array of index-keyed objects ([{"0": 1, "1": 2}, {"0": 3, "1": 4}]) whenever the field is omitted from a partial update/PATCH and its value is carried forward from the original document.

Why?

cloneDataFromOriginalDoc shallow-clones each row of an array value with {...row}. typeof row === 'object' is also true for arrays, so when a row is itself an array (nested arrays, as opposed to the usual array/blocks-field row objects), the object-spread branch runs instead and turns it into an index-keyed object. On a publish operation this trips field validate and is caught, but draft saves skip validation, so the corrupted shape silently persists to the database. Downstream consumers that iterate the tuples then crash with TypeError: object is not iterable.

How?

Check Array.isArray(row) before the generic object check, and clone array rows with [...row] instead of {...row}, preserving their shape. This keeps the same one-level-deep shallow-clone semantics the function already uses for object rows — only the branching changes.

Testing performed

  • Added a unit test (cloneDataFromOriginalDoc.spec.ts) covering nested-array cloning, non-mutation of the original, and the existing object/primitive clone behavior. Verified it fails without the fix and passes with it.
  • Added an integration regression test in test/fields/int.spec.ts reproducing the exact reported flow: create a doc with a json field holding an array-of-arrays, then partially update the doc without touching that field, and assert the stored value is unchanged. Verified it fails without the fix (reproducing the reported corruption exactly) and passes with it.
  • Ran the full test/fields and test/fields-relationship integration suites (sqlite) — all passing, no regressions.
  • tsc --noEmit on packages/payload — no errors.
  • prettier --check and eslint on all changed files — clean.

Fixes #17475

cloneDataFromOriginalDoc shallow-clones each row of an array value
with `{...row}`. When a row is itself an array (e.g. json field data
shaped as an array of coordinate tuples), the spread turns it into an
index-keyed object (`{"0": 1, "1": 2}`), silently corrupting the data
whenever the field is omitted from a partial update and its fallback
value is cloned from the original document.

Check `Array.isArray(row)` before falling back to the object-spread
branch so array rows are cloned as arrays.

Fixes payloadcms#17475
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant