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

  1. Stringify every value: `params: { id: String(row.id) }` or template literals `\`${row.id}\``
  2. Keep numbers out of `params` — pass them via `props` instead, which have no type restriction
  3. 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

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


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)