Fix: Content Entry Data Does Not Match Schema in Astro

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

What Causes This Error?

This error occurs when a data collection entry (JSON, YAML, or TOML file) doesn’t match the schema defined for the collection. This is similar to frontmatter errors but for data-only collections.

The Problem

// src/content/config.ts
const authors = defineCollection({
  type: 'data',
  schema: z.object({
    name: z.string(),
    email: z.string().email(),
    role: z.enum(['admin', 'author', 'guest']),
  }),
});
// src/content/authors/john.json
{
  "name": 123,
  "email": "not-an-email",
  "role": "superuser"
}

The Fix

Match Schema Requirements

// src/content/authors/john.json
{
  "name": "John Doe",
  "email": "john@example.com",
  "role": "author"
}

Common Scenarios

JSON Data Files

// Schema
const products = defineCollection({
  type: 'data',
  schema: z.object({
    name: z.string(),
    price: z.number(),
    inStock: z.boolean(),
  }),
});
// ❌ Invalid
{
  "name": "Widget",
  "price": "29.99",
  "inStock": "yes"
}

// ✅ Valid
{
  "name": "Widget",
  "price": 29.99,
  "inStock": true
}

YAML Data Files

# src/content/settings/site.yaml
# ❌ Invalid
title: 123
maxPosts: "ten"

# ✅ Valid
title: "My Website"
maxPosts: 10

Arrays in Data

const navigation = defineCollection({
  type: 'data',
  schema: z.object({
    items: z.array(z.object({
      label: z.string(),
      url: z.string().url(),
    })),
  }),
});
// ✅ Valid array structure
{
  "items": [
    { "label": "Home", "url": "https://example.com/" },
    { "label": "About", "url": "https://example.com/about" }
  ]
}

Optional Fields in Data

const team = defineCollection({
  type: 'data',
  schema: z.object({
    name: z.string(),
    title: z.string(),
    bio: z.string().optional(),
    avatar: z.string().url().optional(),
  }),
});
// ✅ Optional fields can be omitted
{
  "name": "Jane Smith",
  "title": "Developer"
}

Default Values

const config = defineCollection({
  type: 'data',
  schema: z.object({
    theme: z.string().default('light'),
    itemsPerPage: z.number().default(10),
  }),
});
// ✅ Empty object uses all defaults
{}

// ✅ Override some defaults
{
  "theme": "dark"
}

Nested Data Structures

const i18n = defineCollection({
  type: 'data',
  schema: z.object({
    common: z.object({
      welcome: z.string(),
      goodbye: z.string(),
    }),
    errors: z.record(z.string()),
  }),
});
{
  "common": {
    "welcome": "Hello",
    "goodbye": "Bye"
  },
  "errors": {
    "404": "Not Found",
    "500": "Server Error"
  }
}

Using Data Collections

---
import { getEntry } from 'astro:content';

// Get single data entry
const author = await getEntry('authors', 'john');

// Data is typed according to schema
console.log(author.data.name);   // string
console.log(author.data.email);  // string
---

Multiple File Formats

// Data collections support multiple formats
const data = defineCollection({
  type: 'data',
  schema: z.object({ /* ... */ }),
});

// All valid:
// src/content/data/config.json
// src/content/data/config.yaml
// src/content/data/config.toml

Quick Checklist

  • Use type: 'data' for data collections
  • JSON values must match types exactly
  • Strings need quotes in JSON
  • Numbers should not have quotes
  • Booleans are true/false (not strings)
  • Check error message for specific field