Content collection error: Invalid frontmatter
What causes this
Your Markdown file’s frontmatter doesn’t match the Zod schema defined in your content config. Astro validates every content file against its schema at build time, and any mismatch causes this error.
Common causes:
- A required field is missing from the frontmatter
- A field has the wrong type (string instead of date, string instead of array)
- A date is formatted incorrectly
- An enum value doesn’t match the allowed options
- You added a new required field to the schema but didn’t update existing posts
Fix 1: Check the error message carefully
Astro tells you exactly which file and field failed:
[ERROR] Invalid frontmatter in "src/content/blog/my-post.md"
title: Required
This means the title field is missing from that file’s frontmatter.
Fix 2: Match your frontmatter to the schema
// src/content.config.ts
const blog = defineCollection({
schema: z.object({
title: z.string(),
pubDate: z.coerce.date(),
tags: z.array(z.string()).default([]),
draft: z.boolean().default(false),
}),
});
Your frontmatter must match:
---
title: "My Post"
pubDate: 2026-03-15
tags: ["javascript", "tutorial"]
---
Common type mismatches:
pubDate: "March 15"— use ISO format:pubDate: 2026-03-15tags: javascript— must be an array:tags: ["javascript"]draft: "true"— must be boolean:draft: true
Fix 3: Make fields optional with defaults
If a field shouldn’t be required:
schema: z.object({
title: z.string(),
description: z.string().optional(),
tags: z.array(z.string()).default([]),
draft: z.boolean().default(false),
heroImage: z.string().optional(),
})
.optional() allows the field to be missing. .default() provides a value when missing.
Fix 4: Use z.coerce for flexible types
schema: z.object({
// Accepts both "2026-03-15" string and actual Date
pubDate: z.coerce.date(),
// Accepts both "5" and 5
order: z.coerce.number(),
})
Fix 5: Validate all files at once
# Build to check all files
npx astro build
# Or check specific files
npx astro check
How to prevent it
- Add
.default()or.optional()to schema fields that aren’t always needed - When adding a new required field to the schema, update all existing content files
- Use
z.coerce.date()instead ofz.date()for more flexible date parsing - Keep your schema as simple as possible — only require fields you actually use in templates
- Check our Astro cheat sheet for content collection patterns