Astro: getStaticPaths must be defined — что делать
Запускаешь сборку Astro и получаешь:
[ERROR] getStaticPaths() function is required for dynamic routes.
Make sure that you export a function called getStaticPaths from /src/pages/posts/[slug].astroСообщение прямое: динамическая страница есть, а функции, которая возвращает список параметров для генерации, — нет. Astro в SSG-режиме без неё не понимает, какие страницы создавать.
Это одна из самых регулярных ошибок у людей, которые мигрируют на Astro с Next или Nuxt. Там логика построения динамических роутов другая, и привычка переносится автоматически. У меня в команде эта ошибка ловилась на ревью пять раз, прежде чем все привыкли.
Что это за функция вообще
Astro по умолчанию работает в режиме генерации статики. Если у тебя есть файл src/pages/posts/[slug].astro, фреймворк не знает, какие именно посты существуют. Ты ему говоришь сам:
---
export async function getStaticPaths() {
const posts = await fetchAllPosts();
return posts.map((post) => ({
params: { slug: post.slug },
props: { post },
}));
}
const { post } = Astro.props;
---
<article>
<h1>{post.title}</h1>
<div set:html={post.content} />
</article>Astro вызывает getStaticPaths на сборке, проходит по массиву и для каждого элемента генерит отдельную страницу с нужными параметрами и пропсами.
Если функции нет — конкретно эта ошибка.
Самые частые причины
1. Просто забыл
Поставил [slug].astro, написал шаблон, забыл функцию. Лечится её добавлением.
2. Не export
Объявил, но без export:
// плохо — Astro не увидит
async function getStaticPaths() {
return [...];
}В Astro фреймпсы из frontmatter (между ---) — это нормальный TypeScript-модуль. Чтобы Astro прочитал функцию, она должна быть экспортирована: export async function getStaticPaths().
3. Опечатка в имени
getStaticPath, getStaticPathss, getStaticPaths — Astro смотрит на точное имя. Любая вариация приведёт к той же ошибке.
4. Возвращаешь не массив
Иногда возвращают объект или ничего:
// плохо
export async function getStaticPaths() {
return { '/foo': {...} };
}Должен быть массив объектов с полями params и опционально props:
return [
{ params: { slug: 'a' }, props: { post: {...} } },
{ params: { slug: 'b' }, props: { post: {...} } },
];Когда динамический роут — не SSG
Если у тебя адаптер с SSR (@astrojs/node, @astrojs/vercel, @astrojs/cloudflare и так далее) и страница рендерится на сервере, getStaticPaths не нужен. Но для этого надо явно отметить страницу как SSR. В Astro 5 это делается через export const prerender = false;:
---
export const prerender = false;
const { slug } = Astro.params;
const post = await fetchPost(slug);
---
<article>
<h1>{post.title}</h1>
</article>Без этой строки и без getStaticPaths — будет ошибка. Astro по умолчанию в режиме static, а ты пишешь страницу как серверную. Либо добавь функцию, либо отключи prerender.
Если параметров много
Несколько динамических сегментов — массив объектов с несколькими полями в params:
// src/pages/[lang]/[slug].astro
export async function getStaticPaths() {
return [
{ params: { lang: 'ru', slug: 'about' } },
{ params: { lang: 'en', slug: 'about' } },
{ params: { lang: 'ru', slug: 'contact' } },
];
}Все динамические сегменты файла должны быть в params, иначе будет ошибка про несоответствие.
Пагинация
Часто список постов нужно разбить на страницы. Astro даёт paginate для этого:
// src/pages/blog/[page].astro
import type { GetStaticPathsOptions } from 'astro';
export async function getStaticPaths({ paginate }: GetStaticPathsOptions) {
const posts = await fetchAllPosts();
return paginate(posts, { pageSize: 10 });
}
const { page } = Astro.props;
---
<ul>
{page.data.map((p) => <li>{p.title}</li>)}
</ul>Astro сам сгенерит страницы /blog/1, /blog/2 и так далее. Если этого не сделать — ошибка та же.
Дебаг-трюк
Иногда хочется посмотреть, что вообще возвращает getStaticPaths и почему страница не строится. Делаю так:
export async function getStaticPaths() {
const posts = await fetchAllPosts();
console.log('posts count:', posts.length);
if (posts.length === 0) {
console.warn('No posts to generate');
}
return posts.map((post) => ({
params: { slug: post.slug },
props: { post },
}));
}Если в логе сборки posts count: 0 — функция работает, но данных нет. Тогда это уже проблема источника данных, а не Astro.
Чек-лист
- Файл с динамическими сегментами (
[slug].astro) — есть. export async function getStaticPaths— есть и экспортирована.- Возвращает массив объектов с полем
params. - Если SSR —
export const prerender = false;. - Если пагинация — используешь
paginateиз аргумента.
Когда привыкаешь, добавление getStaticPaths уходит в мышечную память. Astro заставляет тебя думать о том, какие страницы реально существуют, на этапе сборки — это даёт быструю и предсказуемую генерацию без runtime-сюрпризов.