Is there a way to resolve a reference in a custom validation?
Yes, you can resolve references in custom validation, but you'll need to fetch the referenced documents using the Sanity client. The reference data you receive in validation only contains _ref, _type, and _key - it doesn't include the actual document type (like artist or category) that you need.
Here's how to validate that your array contains at least one of each reference type:
import {defineField} from 'sanity'
import {getCliClient} from 'sanity/cli'
// Get a client instance
const client = getCliClient({apiVersion: '2024-01-01'})
export default defineField({
name: 'tags',
title: 'Tags',
type: 'array',
of: [
{
type: 'reference',
to: [{type: 'artist'}, {type: 'category'}],
},
],
validation: (Rule) =>
Rule.required().custom(async (tags) => {
if (!tags || tags.length === 0) {
return true // Let the required() rule handle this
}
// Fetch all referenced documents to get their types
const ids = tags.map(tag => tag._ref)
const documents = await client.fetch(
`*[_id in $ids]{_id, _type}`,
{ids}
)
// Check if we have at least one artist and one category
const hasArtist = documents.some(doc => doc._type === 'artist')
const hasCategory = documents.some(doc => doc._type === 'category')
if (!hasArtist) {
return 'You must include at least one artist'
}
if (!hasCategory) {
return 'You must include at least one category'
}
return true
}),
})Important notes:
Client setup: You need to import and configure the Sanity client. In Studio v3+, use
getCliClientfromsanity/clifor validation contexts.Performance: This validation runs a query on every change, so it adds some overhead. For better performance, you might want to debounce or only run this on certain conditions.
Alternative approach using validation context: If you're using Studio v3, you can also access the client from the validation context:
validation: (Rule) =>
Rule.custom(async (tags, context) => {
const client = context.getClient({apiVersion: '2024-01-01'})
if (!tags || tags.length === 0) return true
const ids = tags.map(tag => tag._ref)
const documents = await client.fetch(
`*[_id in $ids]{_id, _type}`,
{ids}
)
const hasArtist = documents.some(doc => doc._type === 'artist')
const hasCategory = documents.some(doc => doc._type === 'category')
if (!hasArtist) return 'You must include at least one artist'
if (!hasCategory) return 'You must include at least one category'
return true
})This approach is confirmed in this community answer where the same pattern is used to fetch and validate referenced documents. The key insight is that validation only receives the reference structure (_ref, _type, _key), not the actual document data, so you must fetch it explicitly to access document properties like the _type field of the referenced documents.
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.