{"record":{"id":"636d2dd549daf722","repo":"withastro/astro","slug":"invalid-route-file-rest-parameter-must-be-a-s","errorCode":null,"errorMessage":"Invalid route ${file} — rest parameter must be a standalone segment","messagePattern":"Invalid route (.+?) — rest parameter must be a standalone segment","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/astro/src/core/routing/segment.ts","lineNumber":14,"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;\n}\n","sourceCodeStart":1,"sourceCodeEnd":25,"githubUrl":"https://github.com/withastro/astro/blob/52e6c34790cc8ac4e69e6135ace06049867e5c4a/packages/astro/src/core/routing/segment.ts#L1-L25","documentation":"A rest parameter [...param] matches one or more whole path segments, so it is only meaningful when it occupies an entire segment by itself. validateSegment throws when the segment has content before or after [...param] (regex /.+[[.]{{3}}.../ or /[...].+/) AND the file is an .astro page (the .mdx and API-route variants are handled elsewhere). Mixing text with a rest param would make segment-boundary matching ambiguous.","triggerScenarios":"Naming an .astro file where [...slug] is glued to other characters in the same segment: src/pages/foo[...slug].astro, src/pages/[...slug]-bar.astro, src/pages/[lang]/docs[...rest].astro.","commonSituations":"Trying to build URLs like /docs/a/b/c with a single file instead of a directory; prefixing a catch-all (e.g. [locale][...path]); converting a Next.js catch-all route (**/slug) to Astro one-to-one.","solutions":["Move the rest parameter into its own directory segment: rename foo[...slug].astro to foo/[...slug].astro (matches /foo/anything/here).","If you need a static prefix plus one dynamic segment, use a normal param instead: foo/[slug].astro.","For nested docs, combine levels: src/pages/docs/[...slug].astro with getStaticPaths generating the paths."],"exampleFix":"// before\nsrc/pages/docs[...slug].astro   // throws: rest parameter must be a standalone segment\n\n// after\nsrc/pages/docs/[...slug].astro   // matches /docs/getting-started/quickstart","handlingStrategy":"validation","validationCode":"const REST_PARAM_ATTACHED = /.+(\\[\\.\\.\\.[^\\]]+\\])|(\\[\\.\\.\\.[^\\]]+\\]).+/;\n\nfunction isStandaloneRestSegment(segment: string): boolean {\n  return !REST_PARAM_ATTACHED.test(segment);\n}\n// reject pages/ filenames like docs[...slug].astro before build","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Give every [...rest] parameter its own directory segment.","Remember the constraint applies to .astro files specifically; API routes have their own rules.","Model URLs first (/docs/a/b/c), then map segments to file structure, not the reverse."],"tags":["astro","routing","rest-params","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"}