{"record":{"id":"dd39a050f2565d27","repo":"withastro/astro","slug":"invalid-route-file-parameter-name-must-match","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":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/astro/src/core/routing/create-manifest.ts","lineNumber":61,"sourceCode":"\nconst ROUTE_DYNAMIC_SPLIT = /\\[([^[\\]()]+(?:\\([^)]+\\))?)\\]/;\nconst ROUTE_SPREAD = /^\\.{3}.+$/;\n\nexport interface RouteEntry {\n\tpath: string;\n\tisDir: boolean;\n}\n\nfunction 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/**\n * Checks whether two route segments are semantically equivalent.\n *\n * Two segments are equivalent if they would match the same paths. This happens when:\n * - They have the same length.\n * - Each part in the same position is either:\n *   - Both static and with the same content (e.g. `/foo` and `/foo`).","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/withastro/astro/blob/d081033d5fe8e8a68c4bbbad4af9d2deb9c74bca/packages/astro/src/core/routing/create-manifest.ts#L43-L79","documentation":"getParts() in create-manifest.ts rejected a dynamic route segment whose bracketed parameter name is invalid. Parameter names inside [...] must match /^(?:\\.{3})?[\\w$]+$/ — letters, digits, underscore, and dollar sign, optionally prefixed by ... for rest params. The throw is a plain Error (not AstroError) raised during manifest generation.","triggerScenarios":"A file like src/pages/[slug-id].astro (hyphen), [slug.json].astro, [123].astro, or an empty [] bracket; using spaces, dots, or special chars inside the brackets; a rest param like [...slug id].astro.","commonSituations":"Typing a hyphen or dot in a param name; copying a REST-style :slug-id pattern into Astro; tooling auto-generating filenames with disallowed characters.","solutions":["Rename the file so the bracketed name uses only [A-Za-z0-9_$], e.g. [slugId].astro.","For rest params keep the ... prefix directly attached: [...slug].astro.","Remove empty brackets or stray characters from the filename."],"exampleFix":"// before — src/pages/blog/[post-id].astro\n\n// after — src/pages/blog/[postId].astro","handlingStrategy":"validation","validationCode":"function isValidParamName(content: string): boolean {\n  return /^(?:\\.\\.\\.)?[\\w$]+$/.test(content);\n}\n// validate bracketed names when generating route files","typeGuard":"function isValidRouteParam(name: string): boolean {\n  return /^(?:\\.\\.\\.)?[A-Za-z0-9_$]+$/.test(name);\n}","tryCatchPattern":null,"preventionTips":["Restrict dynamic param names to [A-Za-z0-9_$].","Add a CI grep for brackets containing invalid characters in src/pages.","When scaffolding routes programmatically, sanitize param names."],"tags":["routing","filesystem","validation","dynamic-routes"],"backgroundTag":null,"analyzedSha":"d081033d5fe8e8a68c4bbbad4af9d2deb9c74bca","analyzedAt":"2026-08-12T13:37:29.035Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}