Issue setting value of JSON field with document action in Sanity Studio

11 replies
Last updated: Apr 22, 2020
Have a little conundrum for you. I'm trying to set the value of a field with a document action. The field is of type
json
using the sanity-plugin-json-input. I retrieve some values from the document when the user hits publish, produce some JSON from the data and attempt to set the value of a readOnly field before letting the doc publish. The JSON field flashes with what seems to be the correct data for a sec before I get an error from the studio:

{
  "response": {
    "body": {
      "error": {
        "description": "Name contains invalid characters",
        "type": "validationError"
      }
    },
    "url": "<https://o5w1jb7v.api.sanity.io/v1/data/mutate/production?returnIds=true&visibility=async>",
    "method": "POST",
    "headers": {
      "content-length": "86",
      "content-type": "application/json; charset=utf-8"
    },
    "statusCode": 400,
    "statusMessage": ""
  },
  "statusCode": 400,
  "responseBody": "{\n  \"error\": {\n    \"description\": \"Name contains invalid characters\",\n    \"type\": \"validationError\"\n  }\n}",
  "details": {
    "description": "Name contains invalid characters",
    "type": "validationError"
  }
}
I've tried stringifying the JSON before attempting to set the value, but then I get a type error, as the field doesn't want strings. Even tried
JSON.parse(JSON.stringify(...))
in a bit of a desperate try, but nope.
Any idea?
(Love document actions btw
❤️ )
AI Update

I can see you're running into a tricky issue! The "Name contains invalid characters" error is cryptic, but I can help you troubleshoot this based on how document actions and patches work in Sanity.

Understanding the Error

The "Name contains invalid characters" validation error from Sanity's mutation API is typically related to the structure of your patch operation itself, not necessarily the content you're trying to save. This error often appears when there's an issue with how the patch is being constructed or when field names in the patch contain unexpected characters.

The Correct Patch Syntax

When using the patch operation from useDocumentOperation, you need to use the builder pattern, not pass objects directly to execute():

// ✅ Correct syntax with builder pattern
patch.set({frankenCode: jsonData})
patch.execute()

// ❌ Wrong - don't pass arguments to execute()
patch.execute([{set: {frankenCode: jsonData}}])

The patch object returned by useDocumentOperation has methods like .set(), .unset(), .setIfMissing(), etc., that you chain before calling .execute() with no arguments.

Common Causes & Solutions

1. Field Name Issues

The error might occur if your field name contains characters that aren't valid in Sanity's patch path syntax. Field names should be simple identifiers. Double-check that:

  • The field name matches your schema exactly (case-sensitive)
  • There are no special characters, spaces, or unusual formatting
  • You're not accidentally including dots or brackets in the field name itself
// Make sure this matches your schema definition exactly
defineField({
  name: 'frankenCode', // Simple, clean field name
  type: 'json',
  readOnly: true,
})

2. JSON Field Value Format

For the sanity-plugin-json-input plugin, you should pass a plain JavaScript object (not a stringified JSON). You were right to avoid JSON.stringify():

// ✅ Correct - plain object
const jsonData = {
  someKey: "value",
  nested: {
    data: "here"
  }
}
patch.set({frankenCode: jsonData})
patch.execute()

// ❌ Wrong - stringified
patch.set({frankenCode: JSON.stringify(jsonData)})

3. Check for Nested Path Issues

If frankenCode is nested within another object in your schema, you might need to set the full path or the parent object:

// If frankenCode is nested
patch.set({'parentObject.frankenCode': jsonData})
patch.execute()

// Or set the entire parent object
patch.set({parentObject: {...existingData, frankenCode: jsonData}})
patch.execute()

4. Verify Draft vs Published Document

The useDocumentOperation hook should handle this automatically, but verify you're working with the correct document version:

const {patch, publish} = useDocumentOperation(id, type)

// The patch automatically targets the draft if it exists
// But you can log to verify
console.log('Document ID:', id)

Debugging Approach

Add logging to see exactly what's being sent:

const handlePublish = () => {
  const jsonData = processYourData()
  
  console.log('Field name:', 'frankenCode')
  console.log('JSON data:', jsonData)
  console.log('JSON data type:', typeof jsonData)
  console.log('Is plain object:', jsonData?.constructor === Object)
  
  patch.set({frankenCode: jsonData})
  patch.execute()
  publish.execute()
}

The Flash You're Seeing

The fact that the data "flashes" in the UI suggests the patch is being applied locally in the Studio first (optimistic update), but then the mutation API rejects it when trying to persist to the Content Lake. This timing confirms the issue is with the mutation itself.

Alternative Approach: Use the Sanity Client

If the issue persists, you could try using the Sanity client directly to get more detailed error information:

import {useClient} from 'sanity'

// In your document action
const client = useClient({apiVersion: '2024-01-01'})

const handlePublish = async () => {
  const jsonData = processYourData()
  
  try {
    await client
      .patch(id.replace('drafts.', ''))
      .set({frankenCode: jsonData})
      .commit()
    
    publish.execute()
  } catch (error) {
    console.error('Detailed patch error:', error)
    // This might give you more specific information
  }
}

Key Takeaway

The most likely issue is the patch syntax—make sure you're using patch.set({field: value}) followed by patch.execute() with no arguments, not passing patch objects to execute(). Also verify that your field name is a simple identifier without special characters, and that you're passing a plain JavaScript object (not stringified JSON) to the json field.

If none of these solve it, I'd recommend inspecting the exact structure of your jsonData object—sometimes deeply nested or circular structures can cause unexpected validation errors at the API level.

Here is my Document Action code.
import { useState, useEffect } from 'react';
import { useDocumentOperation } from '@sanity/react-hooks';
import { processData } from '../../lib/datamachine';

export default function SetAndPublishAction(props) {
  const { patch, publish } = useDocumentOperation(props.id, props.type);
  const [isPublishing, setIsPublishing] = useState(false);
  const [newSlug, setNewSlug] = useState('');
  useEffect(() => {
    // if the isPublishing state was set to true and the draft has changed
    // to become `null` the document has been published
    if (isPublishing && !props.draft) {
      setIsPublishing(false);
    }
  }, [props.draft]);

  return {
    disabled: publish.disabled,
    label: isPublishing ? 'Publishing…' : 'Publish',
    onHandle: async () => {
      // This will update the button text
      setIsPublishing(true);

      // Set publishedAt to current date and time
      if (props.type === 'report') {
        const { odCsv, cidCsv, urlsJson } = props.draft;
        const frankenData = await processData(cidCsv, odCsv, urlsJson);
        patch.execute([
          {
            set: { frankenCode: frankenData },
          },
        ]);
      }

      // Perform the publish
      publish.execute();

      // Signal that the action is completed
      props.onComplete();
    },
  };
}
Wondering about the error message here:
Name contains invalid characters
. That seems to suggest the issue is not with the JSON? Have you tried submitting a most basic JSON string in
frankenData
(instead of
await processData(cidCsv, odCsv, urlsJson);
) to see if it gets picked up?
Wondering about the error message here:
Name contains invalid characters
. That seems to suggest the issue is not with the JSON? Have you tried submitting a most basic JSON string in
frankenData
(instead of
await processData(cidCsv, odCsv, urlsJson);
) to see if it gets picked up?
Hmm. When I set the line in question to:
set: { frankenCode: { foo: 'bar' } },
It works. Even though that is formatted as a plain JS object the Studio let's it fly without question.
So, it seems the invalid name complaint actually does pertain to the JSON. I'm gonna try to reformat all my keys to something JS-friendly and see what happens.
Seems like it indeed, but that’s useful information too 🙂 Hope the reformatting makes it sing!
That was it. The data was being treated as an JS object, and so it fucked up when it encountered keys with spaces in them. Which is super weird, but thanks a bunch for setting me on the right course. 🙂
Glad you found the solution! And really cool to see you work with document actions after being one of the first persons to try them out 🙂 Should it be somewhere in the (plugin) documentation that data is being treated as a JS object?
I think perhaps this is on the json-plugin? I guess under normal circumstances it expects string input and recombobulate it into json, but when set programmatically it seems to expect neither string or json but a JS-object. I'll do some checking to verify, and perhaps put in a pull request adding a comment about it.
That makes sense, thanks Martin - also for considering to make a PR.
Actually, I guess maybe something should be done with the plugin, unless I'm being very dim at the moment. Because the plugin will not accept valid JSON if it has keys that are not valid JavaScript or even keys that would work in bracket notation, such as
myObject['my cool key']
.

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Was this answer helpful?