withastro/astro · error · Error
Invalid route — rest parameter must be a standalone segment
Error message
Invalid route ${file} — rest parameter must be a standalone segment What it means
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.
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.
Example fix
// before src/pages/docs[...slug].astro // throws: rest parameter must be a standalone segment // after src/pages/docs/[...slug].astro // matches /docs/getting-started/quickstart
Defensive patterns
Strategy: validation
Validate before calling
const REST_PARAM_ATTACHED = /.+(\[\.\.\.[^\]]+\])|(\[\.\.\.[^\]]+\]).+/;
function isStandaloneRestSegment(segment: string): boolean {
return !REST_PARAM_ATTACHED.test(segment);
}
// reject pages/ filenames like docs[...slug].astro before build Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Invalid route — brackets are unbalanced
- Invalid route — parameters must be separated
- The route " " is defined in both " " and " " using SSR…
- getStaticPaths() ignored in dynamic page
- GetStaticPathsRequired
AI-assisted analysis of withastro/astro@52e6c34790 (2026-08-18).
Data as JSON: /api/errors/636d2dd549daf722.
Report an issue: GitHub.
Appendix: source
Thrown at packages/astro/src/core/routing/segment.ts:14
export function validateSegment(segment: string, file = '') {
if (!file) file = segment;
if (segment.includes('][')) {
throw new Error(`Invalid route ${file} \u2014 parameters must be separated`);
}
if (countOccurrences('[', segment) !== countOccurrences(']', segment)) {
throw new Error(`Invalid route ${file} \u2014 brackets are unbalanced`);
}
if (
(/.+\[\.\.\.[^\]]+\]/.test(segment) || /\[\.\.\.[^\]]+\].+/.test(segment)) &&
file.endsWith('.astro')
) {
throw new Error(`Invalid route ${file} \u2014 rest parameter must be a standalone segment`);
}
}
function countOccurrences(needle: string, haystack: string) {
let count = 0;
for (const hay of haystack) {
if (hay === needle) count += 1;
}
return count;
}
View on GitHub (pinned to 52e6c34790)