remix-run/react-router · error

Route segment " " for " " cannot contain " ". If this is…

Error message

Route segment "${segment}" for "${routeId}" cannot contain "${char}".
If this is something you need, upvote this proposal for React Router https://github.com/remix-run/react-router/discussions/9822.

What it means

getRouteSegments() parses each file-based route id into URL segments and rejects raw segments containing '*' or ':' — literal splat/param characters that React Router does not currently support in segment names. The message points to the GitHub discussion (#9822) proposing support, telling you to rename the file instead. It is a hard parse-time error raised while flatRoutes() builds the manifest.

Solutions

  1. Rename the file to remove the '*' or ':' characters
  2. Use the supported '$param' convention for dynamic segments instead of ':param'
  3. If you genuinely need the feature, upvote discussion #9822 and restructure routes meanwhile

Example fix

# before
app/routes/docs.v*:slug.tsx

# after
app/routes/docs.$version.$slug.tsx
Defensive patterns

Strategy: validation

Validate before calling

// reject offending filenames before the route manifest is built
import path from "node:path";
for (const file of routeFiles) {
  for (const seg of path.basename(file).split(".")) {
    if (seg.includes(":") || seg.includes("*")) {
      throw new Error(`Rename ${file}: segment '${seg}' contains ':' or '*'`);
    }
  }
}

Prevention

When it happens

Trigger: A route filename whose segment portion contains a literal '*' or ':', e.g. app/routes/docs.v*:slug.tsx or app/routes/schedule.HH:mm.tsx — pushRouteSegment detects the character in the raw segment and throws.

Common situations: Trying to hand-write ':param' or '*splat' URL syntax into flat-routes filenames; migrating from another router's file conventions where those characters are meaningful; naming files after time/colon patterns.

Related errors


AI-assisted analysis of remix-run/react-router@6beaca3952 (2026-08-18). Data as JSON: /api/errors/98e197cf340bcbfb. Report an issue: GitHub.

Appendix: source

Thrown at packages/react-router-fs-routes/flatRoutes.ts:363

  | "ESCAPE"
  // we hit a `(` and are now in an optional segment until we hit a `)` or an escape sequence
  | "OPTIONAL"
  // we previously were in a opt fional segment and hit a `[` and are now in an escape sequence until we hit a `]` - take characters literally and skip isSegmentSeparator checks - afterwards go back to OPTIONAL state
  | "OPTIONAL_ESCAPE";

export function getRouteSegments(routeId: string): [string[], string[]] {
  let routeSegments: string[] = [];
  let rawRouteSegments: string[] = [];
  let index = 0;
  let routeSegment = "";
  let rawRouteSegment = "";
  let state: State = "NORMAL";

  let pushRouteSegment = (segment: string, rawSegment: string) => {
    if (!segment) return;

    let notSupportedInRR = (segment: string, char: string) => {
      throw new Error(
        `Route segment "${segment}" for "${routeId}" cannot contain "${char}".\n` +
          `If this is something you need, upvote this proposal for React Router https://github.com/remix-run/react-router/discussions/9822.`,
      );
    };

    if (rawSegment.includes("*")) {
      return notSupportedInRR(rawSegment, "*");
    }

    if (rawSegment.includes(":")) {
      return notSupportedInRR(rawSegment, ":");
    }

    if (rawSegment.includes("/")) {
      return notSupportedInRR(segment, "/");
    }

    routeSegments.push(segment);

View on GitHub (pinned to 6beaca3952)