Skip to main content
Zhimalab
中文

Troubleshooting Astro + React Build Issues

2025-11-26 · 12 min

This document records the build errors, root causes and solutions I hit while setting up an Astro + React static blog and tool site.

1. Content Collection schema type mismatch

Error:

[InvalidContentEntryDataError] posts → hello-world data does not match collection schema.
date: Expected type "string", received "date"

Cause: When you write date: 2025-11-26 in Markdown frontmatter, the YAML parser automatically treats it as a Date object. But we used z.string() in the schema defined in src/content/config.ts.

Solution:

  1. Modify the schema: allow either a date or a string.
    date: z.union([z.string(), z.date()])
  2. Normalize the data: quote the date in Markdown to force it to be a string: date: "2025-11-26".

2. Missing Tailwind plugin

Error:

[ERROR] [postcss] Cannot find module '@tailwindcss/typography'

Cause: tailwind.config.cjs has plugins: [require('@tailwindcss/typography')], but the dependency isn’t installed.

Solution:

npm install -D @tailwindcss/typography

3. Undefined component (missing frontmatter syntax)

Error:

ReferenceError: BaseLayout is not defined

The page shows the import statements from the source, or reports an undefined variable.

Cause: An Astro file must start with --- (three hyphens) to delimit the frontmatter region. If it’s omitted or there’s a blank line above it, Astro treats the import statements as plain HTML text, so the script never runs and the component variable is undefined.

Solution: Make sure the top of the .astro file strictly contains the frontmatter delimiter:

---
import BaseLayout from '../layouts/BaseLayout.astro';
---
<BaseLayout>...</BaseLayout>

4. Dynamic routes missing getStaticPaths

Error:

GetStaticPathsRequired: getStaticPaths() function is required for dynamic routes.

Cause: Astro is static site generation (SSG) by default. For dynamic routes like src/pages/blog/[slug].astro, Astro needs to know at build time exactly which pages to generate (e.g. /blog/hello-world).

Solution: Export a getStaticPaths function in the dynamic route file:

export async function getStaticPaths() {
  const posts = await getCollection('posts');
  return posts.map(p => ({ params: { slug: p.slug } }));
}

5. Compiler error reading 'exports' (API misuse)

Error:

[UnknownCompilerError] [astro:build] Cannot read properties of undefined (reading 'exports')

This is an obscure compiler-level error that usually masks a real logic bug in the code.

Cause: The code misused the return value of entry.render():

// wrong way
const { Content, data } = await entry.render();

entry.render() returns { Content, headings, ... } — it does not include data. The data (frontmatter) actually lives on the entry object itself (entry.data). Destructuring a property that doesn’t exist causes downstream rendering/compilation failures.

Solution:

// correct way
const { Content } = await entry.render();
const data = entry.data;

💡 Lessons and best practices

  1. Be rigorous about Astro file structure: always check for --- at the top of .astro files. This is the most common beginner gotcha and causes baffling “Variable not defined” errors.
  2. Understand the Content Collections API:
    • getCollection gets a list.
    • getEntry gets a single entry.
    • entry.data accesses the frontmatter data.
    • entry.render() gets the rendered component <Content />.
    • Don’t confuse the entry object with the result of render().
  3. Think in SSG terms: for dynamic routes, first ask “where does the data come from?” and implement getStaticPaths.
  4. Type safety: use the Content Collections schema (zod) to catch data format errors early, rather than only failing when the page renders.
  5. Build debugging: when you hit obscure compiler errors (like reading 'exports'), it’s often a side effect of a code logic bug (undefined variable, wrong property access). Try reverting recent changes or checking the API call signature.