{"record":{"id":"7b7fe711b1ced7e4","repo":"withastro/astro","slug":"invalid-route-file-parameters-must-be-separat","errorCode":null,"errorMessage":"Invalid route ${file} — parameters must be separated","messagePattern":"Invalid route (.+?) — parameters must be separated","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/astro/src/core/routing/segment.ts","lineNumber":5,"sourceCode":"export function validateSegment(segment: string, file = '') {\n\tif (!file) file = segment;\n\n\tif (segment.includes('][')) {\n\t\tthrow new Error(`Invalid route ${file} \\u2014 parameters must be separated`);\n\t}\n\tif (countOccurrences('[', segment) !== countOccurrences(']', segment)) {\n\t\tthrow new Error(`Invalid route ${file} \\u2014 brackets are unbalanced`);\n\t}\n\tif (\n\t\t(/.+\\[\\.\\.\\.[^\\]]+\\]/.test(segment) || /\\[\\.\\.\\.[^\\]]+\\].+/.test(segment)) &&\n\t\tfile.endsWith('.astro')\n\t) {\n\t\tthrow new Error(`Invalid route ${file} \\u2014 rest parameter must be a standalone segment`);\n\t}\n}\n\nfunction countOccurrences(needle: string, haystack: string) {\n\tlet count = 0;\n\tfor (const hay of haystack) {\n\t\tif (hay === needle) count += 1;\n\t}\n\treturn count;","sourceCodeStart":1,"sourceCodeEnd":23,"githubUrl":"https://github.com/withastro/astro/blob/52e6c34790cc8ac4e69e6135ace06049867e5c4a/packages/astro/src/core/routing/segment.ts#L1-L23","documentation":"Astro compiles pages/ filenames into route patterns where each [param] is a placeholder. Two parameter groups placed directly next to each other, like [id][slug], are rejected by validateSegment because without a literal separator Astro cannot build an unambiguous matching regex (where does id end and slug begin?). Only the adjacent-bracket pattern '][' triggers this specific message.","triggerScenarios":"Creating a file in src/pages (or src/pages/api, or a custom pages dir) whose name or directory segment contains two bracket groups with nothing between them: src/pages/[id][slug].astro, src/pages/api/[a][b].json.ts, or two rest params [...a][...b].astro.","commonSituations":"Scaffolding nested-resource URLs like /users/:id/posts/:slug in one filename; renaming files quickly with an editor; porting :id:slug-style routes from other frameworks; typo when splitting an existing dynamic route.","solutions":["Put a literal separator between the params: rename [id][slug].astro to [id]-[slug].astro (matches /123-hello).","Or make them real path segments: move to src/pages/[id]/[slug].astro (matches /123/hello)."],"exampleFix":"// before\nsrc/pages/[lang][slug].astro   // throws: parameters must be separated\n\n// after\nsrc/pages/[lang]-[slug].astro   // matches /en-hello-world","handlingStrategy":"validation","validationCode":"// run in CI or a predev/prebuild script over your pages directory\nimport { glob } from 'node:fs/promises';\n\nfor await (const file of glob('src/pages/**/*')) {\n  const segment = file.split('/').pop()!;\n  if (segment.includes('][')) {\n    throw new Error(`Route file ${file} has adjacent [param][param] segments`);\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["One bracket group per literal chunk; separate params with '-' or '/'.","Add a lint/CI check on filenames under pages/ before astro build runs.","When scaffolding routes from a URL list, derive filenames programmatically instead of by hand."],"tags":["astro","routing","file-naming","dynamic-routes","build-time"],"backgroundTag":"route-parameter-validation-failed","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"}