withastro/astro · error · Error

Invalid route — parameters must be separated

Error message

Invalid route ${file} — parameters must be separated

What it means

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.

Solutions

  1. Put a literal separator between the params: rename [id][slug].astro to [id]-[slug].astro (matches /123-hello).
  2. Or make them real path segments: move to src/pages/[id]/[slug].astro (matches /123/hello).

Example fix

// before
src/pages/[lang][slug].astro   // throws: parameters must be separated

// after
src/pages/[lang]-[slug].astro   // matches /en-hello-world
Defensive patterns

Strategy: validation

Validate before calling

// run in CI or a predev/prebuild script over your pages directory
import { glob } from 'node:fs/promises';

for await (const file of glob('src/pages/**/*')) {
  const segment = file.split('/').pop()!;
  if (segment.includes('][')) {
    throw new Error(`Route file ${file} has adjacent [param][param] segments`);
  }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of withastro/astro@52e6c34790 (2026-08-18). Data as JSON: /api/errors/7b7fe711b1ced7e4. Report an issue: GitHub.

Appendix: source

Thrown at packages/astro/src/core/routing/segment.ts:5

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)