{"record":{"id":"a5d0fd21213ef705","repo":"withastro/astro","slug":"missing-parameter-part-content","errorCode":null,"errorMessage":"Missing parameter: ${part.content}","messagePattern":"Missing parameter: (.+?)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/astro/src/core/routing/generator.ts","lineNumber":28,"sourceCode":"function sanitizeParams(params: Record<string, string | number>): Record<string, string | number> {\n\treturn Object.fromEntries(\n\t\tObject.entries(params).map(([key, value]) => {\n\t\t\tif (typeof value === 'string') {\n\t\t\t\treturn [key, value.normalize().replace(/#/g, '%23').replace(/\\?/g, '%3F')];\n\t\t\t}\n\t\t\treturn [key, value];\n\t\t}),\n\t);\n}\n\nfunction getParameter(part: RoutePart, params: Record<string, string | number>): string | number {\n\tif (part.spread) {\n\t\treturn params[part.content.slice(3)] ?? '';\n\t}\n\n\tif (part.dynamic) {\n\t\tif (params[part.content] === undefined) {\n\t\t\tthrow new TypeError(`Missing parameter: ${part.content}`);\n\t\t}\n\n\t\treturn params[part.content];\n\t}\n\n\treturn part.content\n\t\t.normalize()\n\t\t.replace(/\\?/g, '%3F')\n\t\t.replace(/#/g, '%23')\n\t\t.replace(/%5B/g, '[')\n\t\t.replace(/%5D/g, ']');\n}\n\nfunction getSegment(segment: RoutePart[], params: Record<string, string | number>): string {\n\tconst segmentPath = segment.map((part) => getParameter(part, params)).join('');\n\n\treturn segmentPath ? collapseDuplicateLeadingSlashes('/' + segmentPath) : '';\n}","sourceCodeStart":10,"sourceCodeEnd":46,"githubUrl":"https://github.com/withastro/astro/blob/52e6c34790cc8ac4e69e6135ace06049867e5c4a/packages/astro/src/core/routing/generator.ts#L10-L46","documentation":"`getRouteGenerator` composes concrete paths from a params object: every dynamic (non-spread) route part must find a defined value in `params`, or it throws `TypeError: Missing parameter: <name>`. It is reached mainly through `stringifyParams`, which keys `getStaticPaths()` results — and note that `stringifyParams` drops `undefined` values before generating, so an undefined or omitted param for a dynamic segment lands here. Spread (`...rest`) params are optional and default to empty string.","triggerScenarios":"`getStaticPaths()` for `src/pages/blog/[lang]/[slug].astro` returning `[{ params: { lang: 'en' } }]` (slug missing); a typo'd key (`{ slugs: 'x' }` vs the file's `[slug]`); values that are `undefined` after filtering, e.g. `{ slug: post.slug }` where `post.slug` is undefined; consuming `generatePattern`-style utilities (e.g. sitemap or route-stringify helpers) with incomplete params.","commonSituations":"Optional CMS fields that sometimes yield undefined slugs; refactoring filenames without updating params keys; building path strings from partial objects in integrations.","solutions":["Supply a concrete string for every dynamic segment named in the file (`[lang]/[slug]` needs both `lang` and `slug`)","Check for typos between the bracket name in the filename and the keys in `params`","Default or filter undefined values before returning: `params: { slug: post.slug ?? post.id }`","Remember spread params (`[...rest]`) are the only optional ones"],"exampleFix":"// before — src/pages/blog/[lang]/[slug].astro\nexport async function getStaticPaths() {\n  return [{ params: { lang: 'en' } }]; // slug missing → TypeError\n}\n\n// after\nreturn [{ params: { lang: 'en', slug: 'hello' } }];","handlingStrategy":"type-guard","validationCode":"// Assert completeness before returning getStaticPaths entries\nconst required = ['lang', 'slug']; // names inside the file's brackets\nconst complete = paths.every((p) => hasAllParams(required, p.params));\nif (!complete) throw new Error('getStaticPaths entry missing a dynamic param');","typeGuard":"// Every dynamic (non-spread) param must be a defined string\nexport function hasAllParams(required: string[], params: Record<string, unknown>): boolean {\n  return required.every((k) => typeof params[k] === 'string');\n}","tryCatchPattern":null,"preventionTips":["Derive params from the same object graph that defines the route's data so keys can't drift","Default or skip entries with optional values: `{ slug: item.slug ?? item.id }` or `.filter()`","Only spread (`[...rest]`) params are optional — everything else in brackets must be provided"],"tags":["getstaticpaths","params","routing","build","typeerror"],"backgroundTag":"missing-route-param","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"}