Custom validation rule checking value of referenced object in Sanity.io
Rule.valueOfField() returns a reference to another field's value, but it cannot be used to dereference or access values from referenced documents. It only works for sibling fields in the same object.
When you call Rule.valueOfField('fieldName'), you get back a special object with path and type: Symbol(FIELD_REF) that the validation system uses internally. This is designed for comparing values between fields (like ensuring an end date is after a start date), not for accessing the actual content of referenced documents.
What you CAN do with Rule.valueOfField():
defineField({
name: 'endDate',
type: 'datetime',
validation: rule => rule.min(rule.valueOfField('startDate'))
})This works because it compares literal values of sibling fields.
What you CANNOT do:
You cannot use Rule.valueOfField() to dereference a reference field and check properties of the referenced document. The validation documentation explicitly notes this limitation - rule.valueOfField() only allows referencing sibling fields, and if you need to refer to things outside of this scope, you must use document-level validation.
Solutions for validating referenced document values:
1. Use custom validation with context.getClient()
You can fetch the referenced document within a custom validator:
validation: (Rule) =>
Rule.custom(async (value, context) => {
if (!value?._ref) return true
const client = context.getClient({apiVersion: '2023-01-01'})
.withConfiguration({perspective: 'previewDrafts'})
const referenced = await client.fetch(
`*[_id == $id][0]`,
{id: value._ref}
)
// Now validate based on referenced.someField
if (referenced?.someField !== 'expectedValue') {
return 'Referenced document must have...'
}
return true
})2. Use document-level validation
If you need to check multiple references together, use document-level validation which gives you access to the entire document via context.document:
export default defineType({
name: 'myDoc',
type: 'document',
validation: rule => rule.custom(async (fields, context) => {
// Access fields.myReference here
// Use getClient() to fetch referenced docs if needed
})
})The key limitation is that Rule.valueOfField() only provides literal field values from sibling fields - it won't follow references or dereference them for you. For that, you need to use context.getClient() within a custom validation function to manually fetch the referenced document.
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.