remix-run/react-router · error

The `routeDiscovery.manifestPath` config must be a root-rela

Error message

The `routeDiscovery.manifestPath` config must be a root-relative pathname beginning with a slash (i.e., "/__manifest")

What it means

With lazy route discovery, the client fetches route manifests from `manifestPath` (default `/__manifest`). The value must be a root-relative pathname starting with `/`; anything else — `__manifest`, `manifest.json`, `https://cdn.example.com/__manifest` — fails the `startsWith("/")` check when `manifestPath` is explicitly set alongside `mode: "lazy"`.

Source

Thrown at packages/react-router-dev/config/config.ts:606

      routeDiscovery = {
        mode: "lazy",
        manifestPath: "/__manifest",
      };
    } else {
      routeDiscovery = { mode: "initial" };
    }
  } else if (userRouteDiscovery.mode === "initial") {
    routeDiscovery = userRouteDiscovery;
  } else if (userRouteDiscovery.mode === "lazy") {
    if (!ssr) {
      return err(
        'The `routeDiscovery.mode` config cannot be set to "lazy" when setting `ssr:false`',
      );
    }

    let { manifestPath } = userRouteDiscovery;
    if (manifestPath != null && !manifestPath.startsWith("/")) {
      return err(
        "The `routeDiscovery.manifestPath` config must be a root-relative " +
          'pathname beginning with a slash (i.e., "/__manifest")',
      );
    }

    routeDiscovery = userRouteDiscovery;
  }

  let appDirectory = Path.resolve(root, userAppDirectory || "app");
  let buildDirectory = Path.resolve(root, userBuildDirectory);

  let rootRouteFile = findEntry(appDirectory, "root", { absolute: true });
  if (!rootRouteFile) {
    let rootRouteDisplayPath = Path.relative(
      root,
      Path.join(appDirectory, "root.tsx"),
    );
    return err(

View on GitHub (pinned to 6beaca3952)

Solutions

  1. Prefix the path with a slash: `manifestPath: "/__manifest"` or your custom `/api/manifest`.
  2. Omit `manifestPath` to use the default `/__manifest`.
  3. If you need the manifest elsewhere, remember it is served by your app's origin — keep it root-relative.

Example fix

// before
export default {
  routeDiscovery: { mode: "lazy", manifestPath: "__manifest" },
};

// after
export default {
  routeDiscovery: { mode: "lazy", manifestPath: "/__manifest" },
};
Defensive patterns

Strategy: validation

Validate before calling

function isRootRelative(p: string): boolean {
  return p.startsWith("/");
}
if (manifestPath != null && !isRootRelative(manifestPath)) {
  throw new Error("routeDiscovery.manifestPath must start with '/'");
}

Type guard

function isRootRelativePathname(p: string): p is `/${string}` {
  return p.startsWith("/") && !/^\/\//.test(p);
}

Prevention

When it happens

Trigger: Explicitly configuring `routeDiscovery: { mode: "lazy", manifestPath: "__manifest" }` (missing leading slash) or an absolute URL; the check only runs for non-null values with lazy mode, so `undefined` keeps the default.

Common situations: Customizing the manifest path to avoid conflicts with an existing `/__manifest` route; copying a path constant that is stored without the leading slash; intending a CDN host and putting the full URL in this field (not supported — it is server-relative).

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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