sanity
sanity copied to clipboard
Array item validation leads to `Array item type not found: .undefined`
Describe the bug
When a field of an object item from an array has a validation rule, the validation panel produces this error:
Array item type not found: .undefined
To Reproduce
Steps to reproduce the behavior:
- With the following schema definition
{
name: 'list',
type: 'array',
of: [{
title: 'Item',
type: 'object',
fields: [
{
name: 'title',
type: 'string',
validation: Rule => Rule.required()
},
{
name: 'text',
type: 'string',
},
]
}]
}
- Add an item in the array
- Fill only text
- Click on validation tooltip to open the validation panel
This happens with a basic Rule.required()
validation or with a custom function.
Expected behavior
The validation panel should correctly displays the path to the error.
Additional details
Full schema
import { KeyedSegment, defineType } from "sanity";
import {arrayToJSONMatchPath, extractWithPath} from '@sanity/mutator'
export default defineType({
title: 'Page',
name: 'page',
type: 'document',
fields: [
{
name: 'title',
type: 'string',
},
{
name: 'list',
type: 'array',
of: [{
title: 'Item',
type: 'object',
fields: [
{
name: 'title',
type: 'string',
validation: Rule => Rule.required().custom((currentTitle, {document, path}) => {
if (typeof currentTitle === 'undefined' || !path) return true
const grandParentPath = arrayToJSONMatchPath(path.slice(0, -2))
const list = extractWithPath(grandParentPath, document)?.[0]?.value as {_key: string, title?: string}[] | undefined
const currentKey = (path.at(-2) as KeyedSegment)?._key
if (!list) return true
const hasDuplicates = list
// filter out item that stores the `currentTitle` value
.filter(item => item._key !== currentKey)
// at least one item has the same title that the current one
.some(item => item.title === currentTitle)
if (!hasDuplicates) return true
return `Title '${currentTitle}' is duplicated.`
})
}
]
}]
},
{
name: 'list2',
type: 'array',
of: [{
title: 'Item',
type: 'object',
fields: [
{
name: 'title',
type: 'string',
validation: Rule => Rule.required()
},
{
name: 'text',
type: 'string',
},
]
}]
}
]
})
Which versions of Sanity are you using?
@sanity/cli (global) 3.23.1 (up to date)
@sanity/eslint-config-studio 3.0.1 (up to date)
@sanity/mutator 3.23.1 (up to date)
@sanity/vision 3.23.1 (up to date)
sanity 3.23.1 (up to date)
What operating system are you using?
MacOS Ventura 13.5.1
Which versions of Node.js / npm are you running?
$ node -v
v20.10.0
$ pnpm -v
8.12.0
Same problem happening to me.
Same for me, any viable workarounds?
Hello everyone! Have you tried adding a name to the object? In the code example, I can see there is only a type and a title defined.
I just experienced the same, and it was solved as @bobinska-dev mentioned: the object of my array didn't have a name. Something like this works now:
fields: [
defineField({
title: 'Features',
type: 'array',
name: 'features',
of: [
defineArrayMember({
title: 'Feature',
type: 'object',
name: 'feature',
fields: [
defineField({
title: 'Text',
type: 'string',
name: 'text',
}),
],
}),
],
}),
]
And I can have custom validations in the document root like:
validation: (Rule: Rule) => [
Rule.custom((module: { features?: { _key: string; text?: string }[] } | undefined, context) => {
if (context.document?.component !== objectName) {
return true
}
if (!module?.features?.length) {
return true
}
const errors = module.features
.map((feature) => {
return feature.text ? true : { _key: feature._key }
})
.filter(isKeyedObject)
return errors.length === 0
? true
: {
message: 'Field is required',
paths: errors.map((error) => ['features', { _key: error._key }, 'text']) as unknown as Path[],
}
}).error(),
]
I can add a new item, while empty, the "text" receives an error, and when is filled, the error is gone. However, another issue started to happen: I get an error "Uncaught error Parent value is not an array, cannot get path segment: [_key == [object Object]]" when I remove an object from the array that had a validation problem.
@fernandesGabriel π wonderful to hear!
-
ask these kinda of questions in the slack community π«‘
-
simplify the validation: add validation for fields in an array item on the field level (so at the text field and use context.parent and context.document to get all values needed for it)
-
make sure you add more validation return true conditions, which take the removal of an item into account (what the field validation does, so better to add these within the object definition)
Try implementing something like this example I published a while ago
I will close this issue, if there are no follow-up questions βΊοΈ