Fix: Content Entry Frontmatter Does Not Match Schema in Astro

Error message:
Content entry frontmatter does not match schema.
Content Collections 2025-01-25

What Causes This Error?

This error occurs when the frontmatter in a content collection entry doesn’t match the schema defined in your content/config.ts. This includes missing required fields, wrong types, or invalid values.

The Problem

// src/content/config.ts
const blog = defineCollection({
  schema: z.object({
    title: z.string(),
    date: z.date(),
    published: z.boolean(),
  }),
});
---
# src/content/blog/post.md
# ❌ Missing required fields, wrong types
title: 123
# date is missing
published: "yes"
---

The Fix

Match Schema Requirements

---
# src/content/blog/post.md
# ✅ Correct types and all required fields
title: "My Blog Post"
date: 2024-01-15
published: true
---

Common Scenarios

Missing Required Field

// Schema requires title
const blog = defineCollection({
  schema: z.object({
    title: z.string(),
    description: z.string(),
  }),
});
---
# ❌ Missing description
title: "My Post"
---

---
# ✅ All required fields present
title: "My Post"
description: "A description of my post"
---

Wrong Type

// Schema expects specific types
const blog = defineCollection({
  schema: z.object({
    title: z.string(),
    views: z.number(),
    tags: z.array(z.string()),
  }),
});
---
# ❌ Wrong types
title: 123           # Should be string
views: "1000"        # Should be number
tags: "tag1, tag2"   # Should be array
---

---
# ✅ Correct types
title: "My Post"
views: 1000
tags:
  - tag1
  - tag2
---

Date Formatting

// Schema expects date
const blog = defineCollection({
  schema: z.object({
    date: z.date(),
  }),
});
---
# ❌ Invalid date format
date: "January 15, 2024"

# ✅ Valid date formats
date: 2024-01-15
date: 2024-01-15T10:30:00Z
---

Optional Fields

// Make fields optional
const blog = defineCollection({
  schema: z.object({
    title: z.string(),
    description: z.string().optional(),
    draft: z.boolean().default(false),
  }),
});
---
# ✅ Optional fields can be omitted
title: "My Post"
# description is optional
# draft defaults to false
---

Enum Values

const blog = defineCollection({
  schema: z.object({
    status: z.enum(['draft', 'published', 'archived']),
  }),
});
---
# ❌ Invalid enum value
status: "pending"

# ✅ Valid enum value
status: "published"
---

Nested Objects

const blog = defineCollection({
  schema: z.object({
    author: z.object({
      name: z.string(),
      email: z.string().email(),
    }),
  }),
});
---
# ✅ Nested object structure
author:
  name: "John Doe"
  email: "john@example.com"
---

Reading Error Messages

Error: blog → post.md frontmatter does not match collection schema.
"date" is required
"title" must be a string

The error tells you:

  • Which collection (blog)
  • Which file (post.md)
  • Which field failed and why

Debugging Schema Issues

// Temporarily make fields optional to debug
const blog = defineCollection({
  schema: z.object({
    title: z.string(),
    date: z.date(),
  }).partial(), // Makes all fields optional temporarily
});

Quick Checklist

  • Check all required fields are present
  • Verify types match schema (string, number, boolean, date)
  • Use correct date format (YYYY-MM-DD)
  • Array fields need YAML list syntax
  • Enum values must match exactly
  • Read error message for specific field