withastro/astro · error · AstroError
PrerenderDynamicEndpointPathCollide
PrerenderDynamicEndpointPathCollide
Error message
Could not render `${pathname}` with an `undefined` param as the generated path will collide during prerendering. Prevent passing `undefined` as `params` for the endpoint's `getStaticPaths()` function, or add an additional extension to the endpoint's filename. What it means
A prerendered endpoint whose last path segment is purely dynamic (e.g. [slug].ts) received an undefined param value. An undefined last param produces an empty trailing segment, colliding with the parent directory's index output. Astro aborts to avoid overwriting another generated file.
Source
Thrown at packages/astro/src/core/render/params-and-props.ts:145
/**
* If we have an endpoint at `src/pages/api/[slug].ts` that's prerendered, and the `slug`
* is `undefined`, throw an error as we can't generate the `/api` file and `/api` directory
* at the same time. Using something like `[slug].json.ts` instead will work.
*/
function validatePrerenderEndpointCollision(
route: RouteData,
mod: ComponentInstance,
params: Params,
) {
if (route.type === 'endpoint' && mod.getStaticPaths) {
const lastSegment = route.segments[route.segments.length - 1];
const paramValues = Object.values(params);
const lastParam = paramValues[paramValues.length - 1];
// Check last segment is solely `[slug]` or `[...slug]` case (dynamic). Make sure it's not
// `foo[slug].js` by checking segment length === 1. Also check here if that param is undefined.
if (lastSegment.length === 1 && lastSegment[0].dynamic && lastParam === undefined) {
throw new AstroError({
...AstroErrorData.PrerenderDynamicEndpointPathCollide,
message: AstroErrorData.PrerenderDynamicEndpointPathCollide.message(route.route),
hint: AstroErrorData.PrerenderDynamicEndpointPathCollide.hint(route.component),
location: {
file: route.component,
},
});
}
}
}
View on GitHub (pinned to d081033d5f)
Solutions
- Stop passing undefined for the last-segment param — always provide a concrete string.
- Add an extension to the filename so the output path differs, e.g. rename [slug].ts to [slug].json.ts.
- Split the route: a dedicated index file for the empty case plus the dynamic file for named values.
Example fix
// before — file: src/pages/api/[slug].ts
export async function getStaticPaths() {
return [{ params: { slug: undefined } }]; // collides
}
// after — rename file to src/pages/api/[slug].json.ts
export async function getStaticPaths() {
return [{ params: { slug: 'item' } }];
} Defensive patterns
Strategy: validation
Validate before calling
function lastParamDefined(params: Record<string, unknown>, key: string): boolean {
return params[key] !== undefined;
}
// in getStaticPaths, filter or fix entries where the last-segment param is undefined Type guard
function hasDefinedLastParam(params: Record<string, unknown>, lastKey: string): params is Record<string, string> {
return typeof params[lastKey] === 'string';
} Prevention
- Never pass undefined for the last dynamic segment of an endpoint; coerce to a real string.
- Give endpoint files an explicit extension (e.g. [slug].json.ts) to decouple the output path.
- Unit-test getStaticPaths output to assert all last params are strings.
When it happens
Trigger: Endpoint file pages/api/[slug].ts with getStaticPaths returning { params: { slug: undefined } }; a rest param endpoint with an empty value; data source yielding undefined for the last param.
Common situations: Migrating a page-style route to an endpoint; conditionally returning undefined params; wanting an 'index' style output from a dynamic endpoint.
Related errors
- PrerenderClientAddressNotAvailable
- ForbiddenRewrite
- NoMatchingStaticPathFound
- ForbiddenRewrite
- [RSS] You can only glob entries within 'src/pages/' when pas
AI-assisted analysis of withastro/astro@d081033d5f (2026-08-12).
Data as JSON: /api/errors/f2f89323c2e83027.
Report an issue: GitHub.