What Causes This Error?
This error occurs when a content entry has an invalid slug value in its frontmatter. The slug must be a string that can be used in URLs.
The Problem
---
# ❌ Invalid slug types
slug: 123
slug: true
slug: null
slug:
- part1
- part2
---
The Fix
Use Valid String Slug
---
# ✅ Valid string slugs
slug: "my-blog-post"
slug: "2024/01/my-post"
slug: "category/subcategory/post"
---
Common Scenarios
Default Slug from Filename
# File: src/content/blog/my-first-post.md
# Default slug is: "my-first-post" (from filename)
# No slug field needed - uses filename
---
title: "My First Post"
---
Custom Slug Override
---
# File: src/content/blog/post-001.md
# ✅ Override the filename-based slug
title: "Welcome to My Blog"
slug: "welcome"
---
<!-- URL will be /blog/welcome instead of /blog/post-001 -->
Slug with Special Characters
---
# ❌ Invalid characters in slug
slug: "My Post Title!"
# ✅ URL-safe slug
slug: "my-post-title"
---
Nested Slug Paths
---
# ✅ Slugs can include path separators
slug: "2024/january/new-year-post"
---
<!-- URL will be /blog/2024/january/new-year-post -->
Computed Slug in Schema
// src/content/config.ts
import { defineCollection, z } from 'astro:content';
const blog = defineCollection({
type: 'content',
schema: z.object({
title: z.string(),
// Don't include slug in schema - it's handled automatically
}),
});
Slug Validation
---
# ✅ Good slugs
slug: "post-title"
slug: "category/post"
slug: "2024-01-15-post"
# ❌ Bad slugs
slug: "" # Empty string
slug: " " # Whitespace only
slug: "/leading" # Leading slash
slug: "trailing/" # Trailing slash
slug: "double//slash" # Double slashes
---
Using Slug in Pages
---
// src/pages/blog/[...slug].astro
import { getCollection } from 'astro:content';
export async function getStaticPaths() {
const posts = await getCollection('blog');
return posts.map((post) => ({
// slug is automatically generated or from frontmatter
params: { slug: post.slug },
props: { post },
}));
}
---
Ensuring Unique Slugs
---
# File 1: src/content/blog/post-a.md
slug: "my-unique-slug"
---
---
# File 2: src/content/blog/post-b.md
slug: "my-unique-slug" # ❌ Duplicate - will cause error
---
Slug from Title
// If you want to generate slugs from titles, do it in the page
import { getCollection } from 'astro:content';
import slugify from 'slugify';
const posts = await getCollection('blog');
const postsWithSlugs = posts.map(post => ({
...post,
computedSlug: slugify(post.data.title, { lower: true }),
}));
Internationalized Slugs
---
# ✅ Slugs can include Unicode (URL-encoded)
slug: "über-uns"
slug: "artículo-español"
---
Quick Checklist
- Slug must be a string
- Use URL-safe characters
- No leading or trailing slashes
- Each slug must be unique within collection
- Empty filename = uses file name as slug
- Keep slugs lowercase and hyphenated