withastro/astro · error · Error
Parameter name must match /^[a-zA-Z0-9_$]+$/
Error message
Parameter name must match /^[a-zA-Z0-9_$]+$/
What it means
`getParts` parses a single path segment of an Astro file-based route into dynamic/static parts. After splitting on `[...]`, the content captured inside a dynamic bracket must satisfy `/^(?:\.\.\.)?[\w$]+$/` — an optional leading spread (`...`) followed by word characters and `$`. Anything else (spaces, hyphens, unicode, dots other than the spread, regex like-parameters with invalid names) throws a plain `Error`.
Source
Thrown at packages/integrations/cloudflare/src/utils/generate-routes-json.ts:18
import type { RoutePart } from 'astro';
// QUESTION could be removed when we expose it from core https://discord.com/channels/830184174198718474/1471406261294727254
// Copied from https://github.com/withastro/astro/blob/3776ecf0aa9e08a992d3ae76e90682fd04093721/packages/astro/src/core/routing/manifest/create.ts#L45-L70
// 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}.+$/;
export function getParts(part: 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('Parameter name must match /^[a-zA-Z0-9_$]+$/');
}
result.push({
content,
dynamic,
spread: dynamic && ROUTE_SPREAD.test(content),
});
});
return result;
}
View on GitHub (pinned to d081033d5f)
Solutions
- Rename the dynamic segment file so the bracketed name matches `/^[a-zA-Z0-9_$]+$/` (e.g. `[user-id]` → `[userId]`).
- For spread/rest params use exactly `[...name]` with a valid identifier name.
- For regex params, ensure the leading name portion is a valid identifier (e.g. `[param]` not `[-param]`).
- Run `astro sync` / `astro build` after renaming to confirm `_routes.json` generation succeeds.
Example fix
// before src/pages/blog/[post-id].astro // after src/pages/blog/[postId].astro
Defensive patterns
Strategy: validation
Validate before calling
const DYNAMIC_NAME = /^(?:\.\.\.)?[a-zA-Z0-9_$]+$/;
function isValidRouteName(segment: string): boolean {
const match = segment.match(/\[([^\]]+)\]/);
return !match || DYNAMIC_NAME.test(match[1]);
}
// before build:
if (!isValidRouteName('[user-id]')) throw new Error('bad route name'); Type guard
function isValidDynamicParam(content: string): boolean {
return /^(?:\.\.\.)?[a-zA-Z0-9_$]+$/.test(content);
} Try / catch
try {
getParts(segment);
} catch (e) {
throw new Error(`Invalid route segment "${segment}": dynamic param names must match /^[a-zA-Z0-9_$]+$/`);
} Prevention
- Use only letters, digits, underscore, and `$` in dynamic route filenames.
- Prefer camelCase for multi-word params.
- Lint route filenames in CI before build.
When it happens
Trigger: Calling `getParts(part)` (indirectly during `_routes.json` generation for the Cloudflare adapter) with a route segment whose bracketed name is malformed, e.g. `src/pages/[my-param].astro`, `src/pages/[foo.bar].astro`, `src/pages/[1num].astro`, or a regex param `[...]` whose captured name fails the word-char test.
Common situations: Naming a dynamic route param with a hyphen (`[user-id]`) or dot. Copying a route filename from another framework. Mixing rest-spread syntax incorrectly (`[...slug.extra]`). Building on Cloudflare triggers `generate-routes-json` which invokes this parser.
Related errors
- [RSS] You can only glob entries within 'src/pages/' when pas
- Invalid route ${file} — brackets are unbalanced
- Invalid route ${file} — rest parameter must be a standalone
- GetStaticPathsRequired
- InvalidGetStaticPathsReturn
AI-assisted analysis of withastro/astro@d081033d5f (2026-08-12).
Data as JSON: /api/errors/342d4318dc92d448.
Report an issue: GitHub.