{"record":{"id":"7346d4bd368b4a6e","repo":"withastro/astro","slug":"getstaticpathsinvalidrouteparam","errorCode":"GetStaticPathsInvalidRouteParam","errorMessage":"Invalid `getStaticPaths()` route parameter for `${key}`. Expected a string or undefined, received `${valueType}` (`${value}`).","messagePattern":"Invalid `getStaticPaths\\(\\)` route parameter for `(.+?)`\\. Expected a string or undefined, received `(.+?)` \\(`(.+?)`\\)\\.","errorType":"exception","errorClass":"AstroError","httpStatus":null,"severity":"error","filePath":"packages/astro/src/core/routing/internal/validation.ts","lineNumber":8,"sourceCode":"import { AstroError, AstroErrorData } from '../../errors/index.js';\n\nconst VALID_PARAM_TYPES = ['string', 'undefined'];\n\n/** Throws error for invalid parameter in getStaticPaths() response */\nexport function validateGetStaticPathsParameter([key, value]: [string, any], route: string) {\n\tif (!VALID_PARAM_TYPES.includes(typeof value)) {\n\t\tthrow new AstroError({\n\t\t\t...AstroErrorData.GetStaticPathsInvalidRouteParam,\n\t\t\tmessage: AstroErrorData.GetStaticPathsInvalidRouteParam.message(key, value, typeof value),\n\t\t\tlocation: {\n\t\t\t\tfile: route,\n\t\t\t},\n\t\t});\n\t}\n}\n","sourceCodeStart":1,"sourceCodeEnd":17,"githubUrl":"https://github.com/withastro/astro/blob/52e6c34790cc8ac4e69e6135ace06049867e5c4a/packages/astro/src/core/routing/internal/validation.ts#L1-L17","documentation":"`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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nreturn posts.map((p) => ({ params: { page: p.pageNumber } })); // number → throws\n\n// after\nreturn posts.map((p) => ({ params: { page: String(p.pageNumber) } }));\n// pass extra data via props: { props: { total: p.total } }","handlingStrategy":"type-guard","validationCode":"// Validate mapped entries before returning them from getStaticPaths\nconst entries = rows.map((r) => ({ params: { id: String(r.id) } }));\nif (!entries.every((e) => isValidStaticPathParams(e.params))) {\n  throw new TypeError('getStaticPaths params must be strings');\n}","typeGuard":"// Narrow a params object to Astro's accepted shape\nexport function isValidStaticPathParams(\n  params: Record<string, unknown>,\n): params is Record<string, string | undefined> {\n  return Object.values(params).every((v) => v === undefined || typeof v === 'string');\n}","tryCatchPattern":null,"preventionTips":["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"],"tags":["getstaticpaths","params","type-validation","build"],"backgroundTag":"getstaticpaths-invalid-param-type","analyzedSha":"52e6c34790cc8ac4e69e6135ace06049867e5c4a","analyzedAt":"2026-08-18T18:48:03.901Z","contentChangedAt":"2026-08-18T18:48:03.901Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}