Skip to content

fix: preserve nested arrays when cloning omitted json field data - #17713

Open
vjymisal0 wants to merge 1 commit into
payloadcms:mainfrom
vjymisal0:fix/17475-clone-array-of-arrays
Open

fix: preserve nested arrays when cloning omitted json field data#17713
vjymisal0 wants to merge 1 commit into
payloadcms:mainfrom
vjymisal0:fix/17475-clone-array-of-arrays

Conversation

@vjymisal0

Copy link
Copy Markdown

What?

cloneDataFromOriginalDoc mangles a JSON field's array-of-arrays value into index-keyed objects when the field is omitted from a partial update.

Why?

Fixes #17475

On a partial payload.update / REST PATCH that omits a json field, getFallbackValue carries the existing value forward via cloneDataFromOriginalDoc (packages/payload/src/fields/hooks/beforeChange/cloneDataFromOriginalDoc.ts). That function shallow-clones each array row with {...row}. typeof an array is 'object', so every nested array row (e.g. [1, 2]) gets spread into { "0": 1, "1": 2 } instead of staying an array. Draft saves skip validation, so the corrupted shape can persist straight to the database; downstream consumers iterating the tuples then throw TypeError: object is not iterable.

How?

In the array branch of cloneDataFromOriginalDoc, check Array.isArray(row) first and recurse into cloneDataFromOriginalDoc for that row instead of falling through to the {...row} object-spread branch. This preserves array shape at any nesting depth while leaving the existing shallow-clone behavior for plain objects untouched.

Test plan

Added an integration test in test/fields/int.spec.ts (json describe block) that creates a json-fields doc with an array-of-arrays value in the schema-free customJSON field, performs a partial update that omits customJSON, and asserts the array structure is preserved on the returned doc.

Note on local verification: I was not able to get a full pnpm install to complete in my environment (network timeouts fetching registry packages partway through a ~9 minute resolve), so I could not run pnpm test:int against this change locally. The fix and test are written to match the existing code's structure and conventions; I'm flagging this explicitly rather than claiming a green run I didn't get. Happy to iterate based on CI results.

…data

cloneDataFromOriginalDoc shallow-cloned every array row with `{...row}`,
which is correct for plain objects but silently turns nested arrays into
index-keyed objects (`[1, 2]` -> `{ "0": 1, "1": 2 }`). This runs whenever
a partial update omits a field and its previous value is carried forward
via getFallbackValue, so a json field storing an array-of-arrays (e.g.
coordinate tuples) gets corrupted on any update that doesn't touch it.
Draft saves skip validation entirely, so the corrupted shape persists.

Recurse into nested arrays instead of spreading them as objects, so array
shape is preserved at any depth while existing object-cloning behavior is
unchanged.

Fixes payloadcms#17475
@vjymisal0 vjymisal0 changed the title fix(payload): preserve nested arrays when cloning omitted json field data fix: preserve nested arrays when cloning omitted json field data Aug 7, 2026
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.

cloneDataFromOriginalDoc mangles json array-of-arrays into index-keyed objects on partial update

1 participant