withastro/astro · error · Error
Invalid route ${file} — parameter name must match /^[a-zA-Z0
Error message
Invalid route ${file} — parameter name must match /^[a-zA-Z0-9_$]+$/ What it means
Thrown by Vercel's `getParts()` route parser when a dynamic route segment's parameter name does not match `/^[a-zA-Z0-9_$]+$/`. Vercel's redirect/route transform needs valid JS-identifier-like names for path parameters; invalid characters make the route unrepresentable.
Source
Thrown at packages/integrations/vercel/src/lib/redirects.ts:22
import type { AstroConfig, IntegrationResolvedRoute, RoutePart } from 'astro';
const pathJoin = nodePath.posix.join;
// Copied from astro/packages/astro/src/core/routing/manifest/create.ts
// Disable eslint as we're not sure how to improve this regex yet
// eslint-disable-next-line regexp/no-super-linear-backtracking
const ROUTE_DYNAMIC_SPLIT = /\[(.+?\(.+?\)|.+?)\]/;
const ROUTE_SPREAD = /^\.{3}.+$/;
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;
}
/**
* Convert Astro routes into Vercel path-to-regexp syntax, which are the input for getTransformedRoutes
*/
function getMatchPattern(segments: RoutePart[][]) {
return segments
.map((segment) => {
return segmentView on GitHub (pinned to d081033d5f)
Solutions
- Rename the param to use only letters, digits, underscore, or `$`: `[userId].astro` or `[user_id].astro`.
- For rest/spread params, keep `[...paramName]` with a valid identifier.
- Avoid hyphens and dots in the bracketed param name; use camelCase or underscores instead.
Example fix
// before: src/pages/blog/[post-slug].astro // after: src/pages/blog/[postSlug].astro
Defensive patterns
Strategy: validation
Validate before calling
function isValidParamName(name: string): boolean {
return /^[a-zA-Z0-9_$]+$/.test(name);
}
// before shipping routes, scan filenames:
for (const f of pageFiles) {
for (const [, param] of f.matchAll(/\[(.+?)\]/g)) {
if (!isValidParamName(param)) throw new Error(`Invalid param '${param}' in ${f}`);
}
} Type guard
function isValidRouteParam(name: string): boolean {
return /^(?:\.\.\.)?[a-zA-Z0-9_$]+$/.test(name);
} Prevention
- Use camelCase or underscores for dynamic route params, never hyphens/dots.
- Add a CI lint that scans `src/pages/**/[*]` filenames.
- Document allowed param name characters for contributors.
When it happens
Trigger: A file/folder like `src/pages/[user-id].astro` (hyphen), `[user.name].astro` (dot), `[user@name].astro`, or a rest spread `[...paths with space]`. Any dynamic param whose content after stripping optional regex group syntax fails `/^(?:\.\.\.)?[\w$]+$/`.
Common situations: Naming route params with hyphens (common mistake from URL conventions). Using dots or special chars. Copying a URL slug pattern directly into a filename.
Related errors
- NoMatchingStaticPathFound
- Invalid route ${file} — parameter name must match /^[a-zA-Z0
- InvalidRedirectDestination
- Missing parameter: ${part.content}
- Invalid route ${file} — parameter name must match /^[a-zA-Z0
AI-assisted analysis of withastro/astro@d081033d5f (2026-08-12).
Data as JSON: /api/errors/c15bf8c363cf7b90.
Report an issue: GitHub.