Build Error: Cannot read properties of null (reading 'mainImage') in Sanity

7 replies
Last updated: Nov 29, 2025
Hello fellow devs, upon doing either npm run build or yarn build i have come across this error, Cannot read properties of null (reading 'mainImage'). How can I tackle this issue? I would appreciate any form of help. Thank you. Ill be attaching the screenshots. First one is page.tsx at '*[project]/app/(user)/post/[slug]/page.tsx*', the error originated from line 53. Second one is post.tsx at '*[project]/schemas/post.ts*', where the type of the field is defined. Third image provides an high level view of the project along with the caught error message in the terminal.
AI Update

Based on your error, it looks like you're trying to access mainImage on a post object that is null during the build process. This is a common issue with Next.js static site generation when some of your posts don't have a mainImage field populated, or when a post document doesn't exist at all.

Here are the most common causes and solutions:

1. Handle null/undefined posts

If the post itself doesn't exist (maybe you're generating paths for posts that were deleted), you need to check if the post exists before accessing its properties:

// In your page.tsx
const post = await getPost(slug);

if (!post) {
  notFound(); // Next.js 13+ App Router
  // or return null / redirect
}

// Now safely access post.mainImage
const imageUrl = post.mainImage ? urlFor(post.mainImage) : null;

2. Handle optional mainImage in your GROQ query

Use the coalesce() function in your GROQ query to provide fallback values:

*[_type == "post" && slug.current == $slug][0] {
  _id,
  title,
  slug,
  "mainImage": coalesce(mainImage, null),
  // or provide a default image object
  body,
  author->
}

3. Add optional chaining in your component

On line 53 of your page.tsx, use optional chaining to safely access mainImage:

// Instead of:
const imageUrl = urlFor(post.mainImage).url();

// Use:
const imageUrl = post.mainImage ? urlFor(post.mainImage).url() : '/default-image.jpg';

// Or with optional chaining:
const imageUrl = post?.mainImage ? urlFor(post.mainImage).url() : null;

4. Make mainImage optional in your schema

In your post.ts schema, ensure mainImage is marked as optional (which it likely already is):

{
  name: 'mainImage',
  title: 'Main Image',
  type: 'image',
  // No 'validation: Rule => Rule.required()' means it's optional
  options: {
    hotspot: true,
  },
}

5. Filter out posts without mainImage during build

If you're using generateStaticParams, you can filter out posts that don't have the required fields:

export async function generateStaticParams() {
  const posts = await client.fetch(`
    *[_type == "post" && defined(mainImage)] {
      "slug": slug.current
    }
  `);
  
  return posts.map((post) => ({
    slug: post.slug,
  }));
}

The defined() function checks if the field exists and isn't null.

Most likely solution

Based on typical Next.js + Sanity setups, you probably need to add a null check before accessing mainImage on line 53. The build process is trying to generate static pages for all posts, and at least one post either doesn't exist or doesn't have a mainImage field populated.

Try wrapping your image rendering logic like this:

{post.mainImage && (
  <Image
    src={urlFor(post.mainImage).url()}
    alt={post.title}
    // ... other props
  />
)}

This will prevent the error by only rendering the image when mainImage actually exists. You can learn more about null handling in GROQ queries to handle these situations at the query level rather than in your component code.

Show original thread
7 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?