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:
- Modify the schema: allow either a date or a string.
date: z.union([z.string(), z.date()]) - 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
- Be rigorous about Astro file structure: always check for
---at the top of.astrofiles. This is the most common beginner gotcha and causes baffling “Variable not defined” errors. - Understand the Content Collections API:
getCollectiongets a list.getEntrygets a single entry.entry.dataaccesses the frontmatter data.entry.render()gets the rendered component<Content />.- Don’t confuse the
entryobject with the result ofrender().
- Think in SSG terms: for dynamic routes, first ask “where does the data come from?” and implement
getStaticPaths. - Type safety: use the Content Collections schema (zod) to catch data format errors early, rather than only failing when the page renders.
- 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.