How do I make a patch request to a document to change its type? This is resulting in an error Cannot modify immutable attribut

11 replies
Last updated: Sep 11, 2020
How do I make a patch request to a document to change its type? This is resulting in an error
Cannot modify immutable attribute \\"_type\\""

{
  "mutations": [
    {
      "patch": {
        "id": "drafts.<document id>",
        "ifRevisionID": "<revision id>",
        "set": {
          "_type": "slidingBanner"
        },
        "unset": [
          "height"
        ]
      }
    }
  ]
}

AI Update

You're getting this error because _type is an immutable attribute in Sanity - it cannot be changed after a document is created. This is by design to maintain data integrity and ensure consistent relationships between documents and their schemas.

Unfortunately, you can't simply patch a document to change its type. Instead, you'll need to create a new document with the desired type and migrate the content from the old document. Here's how to approach this:

Option 1: Manual Migration via API

Create a new document with the correct type and copy over the fields:

import {createClient} from '@sanity/client'

const client = createClient({
  projectId: 'your-project-id',
  dataset: 'your-dataset',
  token: 'your-token',
  apiVersion: '2024-01-01'
})

// Fetch the original document
const originalDoc = await client.getDocument('drafts.<document-id>')

// Create a new document with the new type
const newDoc = {
  ...originalDoc,
  _type: 'slidingBanner', // new type
  _id: undefined, // let Sanity generate a new ID
  _rev: undefined,
  _createdAt: undefined,
  _updatedAt: undefined,
  // Remove fields that don't exist in new schema
  height: undefined
}

// Create the new document
const created = await client.create(newDoc)

// Optionally delete the old document
await client.delete('drafts.<document-id>')

Option 2: Migration Script

For bulk operations, use the @sanity/migration-toolkit which provides utilities for transforming documents at scale.

Important Considerations

  • References: If other documents reference the old document, you'll need to update those references to point to the new document ID
  • Published vs Draft: Handle both the draft and published versions if they exist
  • Schema compatibility: Ensure fields from the old type are compatible with the new type's schema
  • Asset references: These should carry over automatically if the field names match

The immutability of _type is a core design decision in Sanity to prevent schema inconsistencies, so a proper migration is always required when you need to change a document's type.

Note that in this case, this is a top level document which is referenced all over the place. I also am attempting to do this modification to nested objects embedded in other documents.
I am doing a data migration, so this restriction is quite annoying. I can understand that
_type
should not be able to have any other operation other than
set
applied to it, but also preventing
set
? Why?
Note that one of the reasons I want to change the
_type
is because the content sidebar is sorted by the type field, not the title of the schema types, so leaving it alone gives me a giant headache having to explain why it's mostly sorted, but not really.
can't help with the patch issue, but could you create a custom desk structure and sort them yourself?
Something like
S.documentTypeListItems().sort( /* sort by title */ )
Haven't tried to do that for the content sorting, but that seems incredibly silly to need to recreate a component because the default sort is on a visually hidden field instead of the visually prominent title.
I'll have to throw that on my checklist of things to do anyway, since there are some document types I've created that are purely administrative, so I want to implement grouping of document types.

Alas, WYSIWYG editing is higher on my priority list for the higher complexity schemas though.
export default () =>
  S.list()
    .title('Content')
    .items(
      S.documentTypeListItems().sort((a, b) =>
        a.spec.title.localeCompare(b.spec.title),
      ),
    );
hah, well best of luck with it either way!
Thanks for the tip though, saved that for later when I inevitably start bashing my head against my keyboard trying to remember why I know I dont know how to do that.
Hi, this is tricky one since _type is immutable you have to do a full on migration to rename it. Here's a snippet that should help you on the way https://www.github.com/sanity-io/sanity-recipes/tree/master/snippets%2FmigrateDocumentType.js
Ugh. That script doesn't look like it'd handle a deeply nested reference in there. Yeah, gonna pass on renaming the type for now.

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?