withastro/astro · error · AstroError
GetStaticPathsInvalidRouteParam
GetStaticPathsInvalidRouteParam
Error message
Invalid `getStaticPaths()` route parameter for `${key}`. Expected a string or undefined, received `${valueType}` (`${value}`). What it means
`getStaticPaths()` param values are restricted to strings (or `undefined`, which drops the param from the generated path). `validateGetStaticPathsParameter` checks `typeof value` against `['string', 'undefined']` for every entry — via `stringifyParams` while keying static paths — and throws `GetStaticPathsInvalidRouteParam` reporting the key, the received type, and the value, with the route file attached as location.
Solutions
- Stringify every value: `params: { id: String(row.id) }` or template literals `\`${row.id}\``
- Keep numbers out of `params` — pass them via `props` instead, which have no type restriction
- Type your helper: build params as `Record<string, string>` so TS flags number leaks
Example fix
// before
return posts.map((p) => ({ params: { page: p.pageNumber } })); // number → throws
// after
return posts.map((p) => ({ params: { page: String(p.pageNumber) } }));
// pass extra data via props: { props: { total: p.total } } Defensive patterns
Strategy: type-guard
Validate before calling
// Validate mapped entries before returning them from getStaticPaths
const entries = rows.map((r) => ({ params: { id: String(r.id) } }));
if (!entries.every((e) => isValidStaticPathParams(e.params))) {
throw new TypeError('getStaticPaths params must be strings');
} Type guard
// Narrow a params object to Astro's accepted shape
export function isValidStaticPathParams(
params: Record<string, unknown>,
): params is Record<string, string | undefined> {
return Object.values(params).every((v) => v === undefined || typeof v === 'string');
} Prevention
- Wrap values in `String(...)` or template literals the moment they enter `params`
- Pass numbers/objects through `props`, never `params`
- Type helpers as `Record<string, string>` so TS rejects number leaks at the source
When it happens
Trigger: Returning `[{ params: { id: 42 } }]` (number), `{ page: 2 }`, `{ published: true }`, or nested objects/arrays in `params`; params built from `URLSearchParams.get()`-adjacent APIs or DB rows with numeric IDs; numbers sneaking in via spread from JSON data.
Common situations: Numeric database IDs passed straight into params; porting route handlers whose params came as strings and now come parsed from JSON; refactors that compute page numbers inline in the map.
Related errors
- Missing parameter
- GetStaticPathsExpectedParams
- Internal Warning: route cache overwritten.
- PageNumberParamNotFound
- PrerenderDynamicEndpointPathCollide
AI-assisted analysis of withastro/astro@52e6c34790 (2026-08-18).
Data as JSON: /api/errors/7346d4bd368b4a6e.
Report an issue: GitHub.
Appendix: source
Thrown at packages/astro/src/core/routing/internal/validation.ts:8
import { AstroError, AstroErrorData } from '../../errors/index.js';
const VALID_PARAM_TYPES = ['string', 'undefined'];
/** Throws error for invalid parameter in getStaticPaths() response */
export function validateGetStaticPathsParameter([key, value]: [string, any], route: string) {
if (!VALID_PARAM_TYPES.includes(typeof value)) {
throw new AstroError({
...AstroErrorData.GetStaticPathsInvalidRouteParam,
message: AstroErrorData.GetStaticPathsInvalidRouteParam.message(key, value, typeof value),
location: {
file: route,
},
});
}
}
View on GitHub (pinned to 52e6c34790)