{"record":{"id":"485899d98354ffd2","repo":"withastro/astro","slug":"invalid-route-file-parameter-name-must-match-485899","errorCode":null,"errorMessage":"Invalid route ${file} — parameter name must match /^[a-zA-Z0-9_$]+$/","messagePattern":"Invalid route (.+?) — parameter name must match /\\^\\[a-zA-Z0-9_\\$\\]\\+\\$/","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/astro/src/core/routing/parts.ts","lineNumber":17,"sourceCode":"import type { RoutePart } from '../../types/public/index.js';\n\n// Disable eslint as we're not sure how to improve this regex yet\n// eslint-disable-next-line regexp/no-super-linear-backtracking\nconst ROUTE_DYNAMIC_SPLIT = /\\[(.+?\\(.+?\\)|.+?)\\]/;\nconst ROUTE_SPREAD = /^\\.{3}.+$/;\n\nexport function getParts(part: string, file: string) {\n\tconst result: RoutePart[] = [];\n\tpart.split(ROUTE_DYNAMIC_SPLIT).map((str, i) => {\n\t\tif (!str) return;\n\t\tconst dynamic = i % 2 === 1;\n\n\t\tconst [, content] = dynamic ? /([^(]+)$/.exec(str) || [null, null] : [null, str];\n\n\t\tif (!content || (dynamic && !/^(?:\\.\\.\\.)?[\\w$]+$/.test(content))) {\n\t\t\tthrow new Error(`Invalid route ${file} — parameter name must match /^[a-zA-Z0-9_$]+$/`);\n\t\t}\n\n\t\tresult.push({\n\t\t\tcontent,\n\t\t\tdynamic,\n\t\t\tspread: dynamic && ROUTE_SPREAD.test(content),\n\t\t});\n\t});\n\n\treturn result;\n}\n","sourceCodeStart":1,"sourceCodeEnd":29,"githubUrl":"https://github.com/withastro/astro/blob/52e6c34790cc8ac4e69e6135ace06049867e5c4a/packages/astro/src/core/routing/parts.ts#L1-L29","documentation":"The routing layer keeps a standalone copy of the segment parser (`getParts` in `core/routing/parts.ts`, used by `parse-route.ts` and other routing utilities, parallel to the one in `create-manifest.ts`). It splits each segment on `[...]` groups and requires dynamic content to match `/^(?:\\.\\.\\.)?[\\w$]+$/` — an optional `...` spread prefix, then only `[A-Za-z0-9_$]`. Hyphens, dots, spaces, or unicode inside brackets make the param unusable as an identifier, so parsing throws this plain Error naming the file.","triggerScenarios":"Routes like `src/pages/[my-slug].astro`, `src/pages/[slug.json].ts`, `src/pages/[...path-segment].astro`, or unicode names like `[categoría]`; tooling that calls the route-parsing API (parse-route/getParts) directly on generated or user-supplied filenames; renaming directories into bracket notation with invalid characters.","commonSituations":"Kebab-case param names chosen to mirror URL style; scaffolders injecting arbitrary strings into filenames; sharing route-parsing helpers with external route sources (e.g. CMS-defined routes).","solutions":["Rename the param to only letters/digits/`_`/`$` (e.g. `[mySlug].astro`) — hyphens remain fine in the URL value, not the param name","Update `getStaticPaths()` params and `Astro.params` reads to the new name","Lint `src/pages` for bracket contents failing `/^(?:\\.\\.\\.)?[\\w$]+$/` so invalid names fail loudly in CI"],"exampleFix":"# before\nsrc/pages/blog/[my-slug].astro\n\n# after\nsrc/pages/blog/[mySlug].astro\n# and update: getStaticPaths() → [{ params: { mySlug: 'some-value' } }]","handlingStrategy":"type-guard","validationCode":"# CI scan over pages (and any externally sourced route names)\nfor f in $(find src/pages -name '*\\[*\\]*'); do\n  grep -oE '\\[[^]/]+\\]' <<< \"$f\" | tr -d '[]' | while read -r p; do\n    p=\"${p#...}\"\n    isValidRouteParamName \"$p\" || { echo \"invalid param '$p' in $f\"; exit 1; }\n  done\ndone","typeGuard":"// Same rule Astro enforces when parsing segments\nexport function isValidRouteParamName(name: string): boolean {\n  return /^(?:\\.\\.\\.)?[\\w$]+$/.test(name);\n}","tryCatchPattern":null,"preventionTips":["Restrict bracket param names to `[A-Za-z0-9_$]` (plus `...` spread prefix)","Validate route filenames from generators/CMS sources before writing them into src/pages","Run the filename lint in CI to catch renames and scaffolder output"],"tags":["file-based-routing","routing","naming","route-parsing"],"backgroundTag":"invalid-route-parameter-name","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"}