Skip to content

fix(visual-editing-csm): decode all-numeric _key as a key, not an array index - #3564

Open
voidhrithik wants to merge 2 commits into
sanity-io:mainfrom
voidhrithik:fix/numeric-array-key-reorder
Open

fix(visual-editing-csm): decode all-numeric _key as a key, not an array index#3564
voidhrithik wants to merge 2 commits into
sanity-io:mainfrom
voidhrithik:fix/numeric-array-key-reorder

Conversation

@voidhrithik

@voidhrithik voidhrithik commented Jul 29, 2026

Copy link
Copy Markdown

Fixes #3467.

An all-numeric _key was decoding as an array index, so reordering one of those items threw Found no matching array element to replace.

The encode side writes an index and a _key identically:

if (typeof segment === 'number') str += `${segment}`      // array:5
if (segment._key)                str += `${segment._key}` // array:342330179449

which leaves urlStringToPath to break the tie, and RE_SEGMENT_WITH_INDEX matched any run of digits and got tested first. So the key came back a number, decodeSanityString stringified it to sections[342330179449], getArrayItemKeyAndParentPath found no _key, and the reorder ran remove(~~"342330179449"), which int32-truncates to -1267204231.

The fix is the quantifier:

-const RE_SEGMENT_WITH_INDEX = /^([\w-]+):(0|[1-9][0-9]*)$/
+const RE_SEGMENT_WITH_INDEX = /^([\w-]+):(0|[1-9][0-9]{0,8})$/

Nine digits max, so anything longer falls through to the key branch. That covers every randomKey output, since those are 12 characters. Leading-zero keys already worked. A short hand-authored key like 12345 stays ambiguous, and no magnitude rule fixes that one, so this keeps to the randomKey case the issue reports.

I started out with a MAX_ARRAY_INDEX = 2 ** 32 - 2 constant and a second condition in the loop. Same behaviour, four more lines and a second place to look, so I dropped it. Happy to put it back if you would rather have the bound spelled out than the regex short.

Testing

Three cases added to urlStringToPath.test.ts. The existing array:123 assertion still holds.

I also ran the chain from the issue, createDataAttribute(['sections', {_key}]) through decodeSanityNodeData to getArrayItemKeyAndParentPath, against this branch and against main. On main:

_key=342330179449   sections[342330179449]          explicit=false
_key=123456789012   sections[123456789012]          explicit=false
_key=999999999999   sections[999999999999]          explicit=false
_key=000000000001   sections[_key=="000000000001"]  explicit=true
_key=abc123def456   sections[_key=="abc123def456"]  explicit=true

All six pass on this branch, and ['items', 0], ['items', 5], ['items', 999999999] decode as indexes either way.

@changeset-bot

changeset-bot Bot commented Jul 29, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 819c8a7

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 5 packages
Name Type
@sanity/visual-editing-csm Patch
@sanity/core-loader Patch
@sanity/react-loader Patch
@sanity/visual-editing Patch
@sanity/svelte-loader Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercel Bot commented Jul 29, 2026

Copy link
Copy Markdown

@voidhrithik is attempting to deploy a commit to the Sanity Sandbox Team on Vercel.

A member of the Team first needs to authorize it.

…ay index

pathToUrlString serialises an array index and a _key to the same form, and
RE_SEGMENT_WITH_INDEX matched any run of digits, so a _key like 342330179449
decoded back as a number. decodeSanityString then stringified it to
sections[342330179449], hasExplicitKey came out false, and drag-and-drop
reorder ran remove(~~"342330179449"), which truncates to -1267204231 and
matches no element.

Cap the index pattern at 9 digits. A longer all-digit segment cannot index
any real array, so it now falls through to RE_SEGMENT_WITH_KEY.

Fixes sanity-io#3467
@voidhrithik

Copy link
Copy Markdown
Author

@stipsan could you approve the CI run when you get a chance? It's behind the first-time-contributor gate, so nothing has run yet.

I checked it against main too, where the all-digit keys come back with hasExplicitKey false, same as the issue describes. Index paths decode the same either way.

Not chasing a review, just the button.

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.

Drag-and-drop reorder fails for array items with an all-numeric _key

1 participant