Skip to content

encodeDataAttribute throws 'invalid segment' for {_key} path segments due to unresolved _index in jsonPathToMappingPath #1221

Description

@ryanleichty

Bug Description

encodeDataAttribute from @sanity/core-loader throws an invalid segment error when called with {_key} path segments (e.g. encodeDataAttribute(['sections', {_key: 'abc'}, 'images', {_key: 'xyz'}])). This makes it impossible to use encodeDataAttribute with array items identified by _key, which is the pattern documented in hydrogen-sanity's README.

Root Cause

The issue is in the interaction between studioPathToJsonPath and jsonPathToMappingPath in @sanity/client/csm:

1. studioPathToJsonPath creates placeholder segments with _index: -1:

// @sanity/client/csm - resolveEditInfo.js
function studioPathToJsonPath(path) {
  return path.map((segment) => {
    // ...
    if (segment._key)
      return { _key: segment._key, _index: -1 }; // ← placeholder, never resolved
    // ...
  });
}

When given {_key: 'abc'}, it produces {_key: 'abc', _index: -1}. The -1 is a sentinel value meaning "index unknown", but nothing ever resolves it to the actual array index. The result data is available in the calling encodeDataAttribute function but is never passed to studioPathToJsonPath for key-to-index resolution.

2. jsonPathToMappingPath rejects _index: -1:

function jsonPathToMappingPath(path) {
  return path.map((segment) => {
    if (typeof segment == "string" || typeof segment == "number")
      return segment;
    if (segment._index !== -1)
      return segment._index;
    throw new Error(`invalid segment:${JSON.stringify(segment)}`); // ← throws here
  });
}

This function converts path segments to numeric indices for CSM mapping lookup, but when _index is -1, it throws instead of falling back to _key-based resolution.

Steps to Reproduce

import { defineEncodeDataAttribute } from '@sanity/core-loader/encode-data-attribute'

const result = {
  sections: [
    { _key: 'abc', _type: 'imageFeature', images: [{ _key: 'xyz', crop: 'square' }] }
  ]
}

const sourceMap = { /* valid CSM from Sanity API */ }
const studioUrl = 'https://my-studio.sanity.studio'

const encodeDataAttribute = defineEncodeDataAttribute(result, sourceMap, studioUrl)

// This throws: "invalid segment: {"_key":"abc","_index":-1}"
encodeDataAttribute(['sections', { _key: 'abc' }, 'images', { _key: 'xyz' }])

Error

Error: invalid segment:{"_key":"abc123","_index":-1}
    at jsonPathToMappingPath (resolveEditInfo.js)
    at resolveMapping (resolveEditInfo.js)
    at resolveEditInfo (resolveEditInfo.js)
    at encodeDataAttribute (encode-data-attribute.js)

Expected Behavior

encodeDataAttribute should resolve {_key} path segments against the result data to determine the actual array index, then use that index for CSM mapping lookup. The result data is already available in the encodeDataAttribute closure but is not used for path resolution.

Suggested Fix

Option A: Resolve _key to _index using the result data in encodeDataAttribute before calling resolveEditInfo:

const encodeDataAttribute = (result, sourceMap, studioUrl, studioPathLike) => {
  if (!sourceMap || !studioUrl) return;
  const resultPath = studioPathToJsonPath(studioPathLike);
  // Resolve _key segments against result data
  const resolvedPath = resolveKeySegments(resultPath, result);
  const editInfo = resolveEditInfo({ resultPath: resolvedPath, ... });
  // ...
};

Option B: Make jsonPathToMappingPath handle _key segments by using _key-based JSON path selectors ([?(@._key=='abc')]) instead of requiring numeric indices, since the CSM may contain either format.

Context

This bug is related to but separate from sanity-io/hydrogen-sanity#185, which tracks a studioUrl serialization issue. Even with studioUrl fixed, encodeDataAttribute fails for {_key} paths due to this bug.

The workaround is to use createDataAttribute from @sanity/core-loader/create-data-attribute instead, which takes explicit document metadata and serializes paths directly without CSM resolution.

Environment

  • @sanity/client: 7.22.0
  • @sanity/core-loader: 2.0.9

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions