Error in custom validation rule for schema in Slack thread

6 replies
Last updated: Aug 18, 2023
Schema validation error. I am trying to write a custom validation rule using the .custom function however I get error
slug: Exception occurred while validating value: name.includes is not a function. (In 'name.includes("Brew")', 'name.includes' is undefined)


{
      title: "Slug",
      name: "slug",
      type: "slug",
      options: {
        source: "title",
        maxLength: 200, // will be ignored if slugify is set
        slugify: (input: string) => {
          const sanitized = input
            .toLowerCase()
            .replace(/\s+/g, "-")
            .replace(/[^a-zA-Z0-9-]/g, "")
            .slice(0, 200);
          return sanitized;
        },
      },
      validation: (Rule) => [
        Rule.required(),
        Rule.custom((name: string) => {
          if (typeof name === "undefined") {
            return true; // Allow undefined values
          }

          // This would crash if we didn't check
          // for undefined values first
          return name.includes("Brew") ? "you can't use Brew" : true;
        }),
      ],
    },

AI Update

I can see the issue you're encountering. The problem is that in your custom validation rule, you're checking the name parameter, but for a slug field, the value structure is different than you might expect.

When validating a slug field, the value passed to your custom validation function is not a simple string—it's an object with a current property that contains the actual slug string.

Here's what's happening:

Rule.custom((name: string) => {
  // `name` here is actually an object like { _type: 'slug', current: 'some-slug' }
  // NOT a string, so name.includes() fails
  return name.includes("Brew") ? "you can't use Brew" : true;
})

The Solution

You need to access the current property of the slug object:

{
  title: "Slug",
  name: "slug",
  type: "slug",
  options: {
    source: "title",
    maxLength: 200,
    slugify: (input: string) => {
      const sanitized = input
        .toLowerCase()
        .replace(/\s+/g, "-")
        .replace(/[^a-zA-Z0-9-]/g, "")
        .slice(0, 200);
      return sanitized;
    },
  },
  validation: (Rule) => [
    Rule.required(),
    Rule.custom((slug) => {
      if (typeof slug === "undefined") {
        return true; // Allow undefined values
      }

      // Access the 'current' property which contains the actual slug string
      if (!slug?.current) {
        return true;
      }

      return slug.current.includes("brew") 
        ? "You can't use 'brew' in the slug" 
        : true;
    }),
  ],
}

Key changes:

  1. Access slug.current instead of treating the value as a string directly
  2. Check if slug?.current exists before calling .includes()
  3. Note: I changed the check to lowercase "brew" since your slugify function converts everything to lowercase

The slug field stores its value as an object: { _type: 'slug', current: 'your-slug-here' }, which is why you need to access the current property. You can see this structure in the Sanity slug type documentation.

Try console.log(name) before the line
return name.includes("Brew") ? "you can't use Brew" : true;
And check what is currently name
I See the problem now. Console.log prints
{_type: "slug", current: "jjj"}

so its name.current. only thing is that I lose the typescript definitions for this input type
It’s normal, you typed
name: string
.Try to declare a type before like so:

interface TypeName {
  _type: 'slug';
  current: string;
}
Then you can use this type here:
Rule.custom((name: TypeName) => {
Thanks very much
Here is the finished custom rule that checks that the slug is all lowercase and no special characters except -

validation: (Rule) => [
        Rule.required(),
        Rule.custom((name: { _type: string; current: string }) => {
          // This would crash if we didn't check
          // for undefined values first
          if (typeof name === "undefined") {
            return true; // Allow undefined values
          }

          let hasSpecialCharacters = /[^\na-z0-9-]/g.test(name.current);
          return hasSpecialCharacters
            ? "Your slug has characters that are not allowed"
            : true;
        }),
      ],
    },

Top! congrats

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?