Auto-populate field based on reference selection: "Cannot assign to read only property" error

2 replies
Last updated: Jun 17, 2021
Hello everyone!Hope someone can help me with an issue. I have 2 fields in object. I’d like to choose something from the array of “reference” at the first field. And depends on it make a request and fill the next field automatically. I’m working with it in a custom validation Rule at the first field, but I have an error “`Error validating value: Cannot assign to read only property 'listingElements' of object '#<Object>`’”

It’s appears on line “`doc.parent.listingElements = productRefs;`”
Is it posible to do what I want? Please contact me in case you know what I’m talking about.
AI Update

I understand your issue! You're running into a fundamental limitation with validation rules - validation rules are meant for validating data, not for modifying it. The doc object you receive in a validation rule is read-only, which is why you're getting that error when trying to assign to doc.parent.listingElements.

The good news is that what you're trying to do (populate one field based on another) is absolutely possible in Sanity, but you need to use a custom input component instead of a validation rule.

Here's the approach:

Create a custom input component that:

  1. Watches the first field's value (the reference selection)
  2. Makes your request when it changes
  3. Updates the second field (listingElements) using the onChange prop with proper patch events

Here's a basic example structure:

import { set, unset } from 'sanity'
import { useEffect } from 'react'
import { useFormValue } from 'sanity'

export function ListingElementsInput(props) {
  const { onChange, value } = props
  
  // Get the value of the first field (adjust path as needed)
  const referenceField = useFormValue(['yourReferenceFieldName'])
  
  useEffect(() => {
    if (referenceField) {
      // Make your request here
      fetchProductRefs(referenceField).then(productRefs => {
        // Update the field value
        onChange(set(productRefs))
      })
    }
  }, [referenceField])
  
  // Render your field UI (or use renderDefault if you want the standard UI)
  return props.renderDefault(props)
}

Then in your schema:

{
  name: 'listingElements',
  type: 'array', // or whatever type
  components: {
    input: ListingElementsInput
  }
}

The key differences from validation:

  • Custom input components have write access via the onChange prop
  • You can use useFormValue() to watch other fields in the document
  • You can make async requests and update the field accordingly

Check out this guide on creating custom input components for more details on the implementation.

Why validation rules don't work for this: Validation rules are purely for checking if data is valid - they run after changes and return errors/warnings. They're intentionally read-only to prevent side effects during validation. Custom input components are the proper extension point for conditional field population and dynamic behavior.

Show original thread
2 replies
You should be able to achieve this by creating a custom Input component - one that renders the standard select menu for the references, and, after it is updated, patches the document to set the value for the second field.
You can't use the validator to set field values, but you can use
Rule.custom
to validate it based on the reference. I.e.:

validation: Rule => Rule.custom((value, context) => {
   // get the parent object
   const parent = context.parent;
   
   // If there is a reference in the first field,
   // make this one required
   if (parent.referencesField.length > 0) {
      return Rule.required()(value);
   }
   // Otherwise, return true (field is valid)
   return true;
 
})
Thank you!

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?