withastro/astro · error · Error
Invalid route — parameter name must match /^[a-zA-Z0-9_$]+$/
Error message
Invalid route ${file} — parameter name must match /^[a-zA-Z0-9_$]+$/ What it means
While creating the route manifest, Astro splits each file path segment on `[...]` groups; any dynamic part's content must match `/^(?:\.{3})?[\w$]+$/` — optionally a `...` spread prefix, then only letters, digits, underscore, and dollar sign. Anything else (hyphens, dots, spaces, unicode) makes the param impossible to treat as a valid identifier, so manifest creation throws this plain Error naming the offending file.
Solutions
- Rename the param to use only `[A-Za-z0-9_$]`, e.g. `[mySlug].astro` — the param value can still contain hyphens at runtime, only the name is restricted
- Update `getStaticPaths()`/`Astro.params` keys to the renamed param
- Scan `src/pages` for bracket segments failing `/^(?:\.\.\.)?[\w$]+$/` to catch all offenders at once
Example fix
# before
src/pages/blog/[my-slug].astro
# after
src/pages/blog/[mySlug].astro
# and update: getStaticPaths() → [{ params: { mySlug: 'some-value' } }] Defensive patterns
Strategy: type-guard
Validate before calling
# CI scan: fail on bracket params with invalid names
find src/pages -name '*\[*\]*' | while read -r f; do
echo "$f" | grep -oE '\[[^]/]+\]' | tr -d '[]' | while read -r p; do
p="${p#...}"; is_valid_param_name "$p" || { echo "invalid param '$p' in $f"; exit 1; }
done
done Type guard
// Mirrors Astro's rule: optional '...' spread, then word chars / $ only
export function isValidRouteParamName(name: string): boolean {
return /^(?:\.\.\.)?[\w$]+$/.test(name);
} Prevention
- Use camelCase for dynamic segment names; keep hyphens for URL values, not param names
- Add the filename scan to CI so scaffolders and renames fail loudly
- Never interpolate user/CMS strings directly into file-based route filenames
When it happens
Trigger: A page or endpoint named `src/pages/[my-slug].astro` (hyphen), `src/pages/[slug.json].ts` (dot inside brackets), `src/pages/[...path-segment].astro`, or `src/pages/[categoría].astro` (unicode); renaming a static folder into bracket notation with invalid characters; generating pages programmatically with unvalidated names.
Common situations: Reaching for kebab-case param names to match URL style; converting a flat route (`/my-slug`) to dynamic and keeping the hyphen; scaffolding scripts that inject arbitrary strings into filenames.
Related errors
- Invalid route — parameter name must match /^[a-zA-Z0-9_$]+$/
- Error generating redirects
- Error generating routes
- Missing parameter
- MissingIndexForInternationalizationError
AI-assisted analysis of withastro/astro@e294953aa8 (2026-08-18).
Data as JSON: /api/errors/dd39a050f2565d27.
Report an issue: GitHub.
Appendix: source
Thrown at packages/astro/src/core/routing/create-manifest.ts:61
const ROUTE_DYNAMIC_SPLIT = /\[([^[\]()]+(?:\([^)]+\))?)\]/;
const ROUTE_SPREAD = /^\.{3}.+$/;
export interface RouteEntry {
path: string;
isDir: boolean;
}
function getParts(part: string, file: string) {
const result: RoutePart[] = [];
part.split(ROUTE_DYNAMIC_SPLIT).map((str, i) => {
if (!str) return;
const dynamic = i % 2 === 1;
const [, content] = dynamic ? /([^(]+)$/.exec(str) || [null, null] : [null, str];
if (!content || (dynamic && !/^(?:\.\.\.)?[\w$]+$/.test(content))) {
throw new Error(`Invalid route ${file} — parameter name must match /^[a-zA-Z0-9_$]+$/`);
}
result.push({
content,
dynamic,
spread: dynamic && ROUTE_SPREAD.test(content),
});
});
return result;
}
/**
* Checks whether two route segments are semantically equivalent.
*
* Two segments are equivalent if they would match the same paths. This happens when:
* - They have the same length.
* - Each part in the same position is either:
* - Both static and with the same content (e.g. `/foo` and `/foo`).View on GitHub (pinned to e294953aa8)