How to fix "Unknown block type undefined" error in Portable Text with Sanity?

16 replies
Last updated: Nov 29, 2025
Hello, I am fetching a doc like this :
const main = await sanity.fetch(groq
    `*[_type == "pages"][pageSlug.current == $pageSlug][0]{
      'hero': blockContent[_type == 'hero'],
      'platforms': blockContent[_type == 'platforms']
    }
    `,{pageSlug}
    )
I am using Portable Text to display components,

const ptComponents = {
    // Components for totally custom types outside the scope of Portable Text
    types: {
        hero: Main,
        platforms: Platforms
    },
  
    // Overrides for specific block styles - in this case just the `h2` style
    block: {
     
    },
  
    // Implements a custom component to handle the `schnauzer` list item type
    list: {
     
    },
  
    // Custom components for marks - note that `link` overrides the default component,
    // while the others define components for totally custom types.
    marks: {

    },
  }

<PortableText components={ptComponents} value={props.main} />
Eventually I get this error

[@portabletext/react] Unknown block type "undefined", specify a component for it in the `components.types` prop
How can I fix this please??
AI Update

The error you're seeing happens because your GROQ query is returning an object structure that doesn't match what Portable Text expects. The issue is in how you're filtering your blockContent array.

When you do 'hero': blockContent[_type == 'hero'], this returns an array of hero blocks, not the blocks themselves in Portable Text format. Then when you pass props.main to <PortableText>, it's receiving an object like { hero: [...], platforms: [...] } rather than a proper Portable Text array of blocks.

Here are two ways to fix this:

Option 1: Pass the arrays separately (recommended)

Instead of passing the entire main object to a single PortableText component, render each section separately:

const main = await sanity.fetch(groq`
  *[_type == "pages" && pageSlug.current == $pageSlug][0]{
    'hero': blockContent[_type == 'hero'],
    'platforms': blockContent[_type == 'platforms']
  }
`, {pageSlug})

// Then render:
<>
  <PortableText components={ptComponents} value={main.hero} />
  <PortableText components={ptComponents} value={main.platforms} />
</>

Option 2: Keep the full blockContent structure

If you want to render everything together in order, fetch the entire blockContent array and let PortableText handle it:

const main = await sanity.fetch(groq`
  *[_type == "pages" && pageSlug.current == $pageSlug][0]{
    blockContent
  }
`, {pageSlug})

// Then render:
<PortableText components={ptComponents} value={main.blockContent} />

The key issue is that Portable Text expects an array of blocks, not an object with nested arrays. Each block in the array should have a _type property that matches your component definitions (hero, platforms, etc.).

Also note: Your GROQ filter syntax should use && instead of chaining multiple [][]. The corrected syntax is *[_type == "pages" && pageSlug.current == $pageSlug][0].

Show original thread
16 replies

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?