remix-run/react-router · error
The `prerender.concurrency` config must be a positive intege
Error message
The `prerender.concurrency` config must be a positive integer if specified.
What it means
When `prerender` is an object with a `concurrency` key, the value must be a positive integer (`Number.isInteger(n) && n > 0`). Any other value — 0, negative numbers, floats like 2.5, `Infinity`, `NaN`, or strings — fails `isValidConcurrencyConfig` and returns this error, because the value is used to size the prerender worker/task pool.
Source
Thrown at packages/react-router-dev/config/config.ts:579
"of string paths, or a function returning a boolean or array of string paths.",
);
}
if (typeof prerender === "object" && "unstable_concurrency" in prerender) {
return err(
"The `prerender.unstable_concurrency` config field has been stabilized as `prerender.concurrency`",
);
}
let isValidConcurrencyConfig =
typeof prerender != "object" ||
!("concurrency" in prerender) ||
(typeof prerender.concurrency === "number" &&
Number.isInteger(prerender.concurrency) &&
prerender.concurrency > 0);
if (!isValidConcurrencyConfig) {
return err(
"The `prerender.concurrency` config must be a positive integer if specified.",
);
}
}
let routeDiscovery: ResolvedReactRouterConfig["routeDiscovery"];
if (userRouteDiscovery == null) {
if (ssr) {
routeDiscovery = {
mode: "lazy",
manifestPath: "/__manifest",
};
} else {
routeDiscovery = { mode: "initial" };
}
} else if (userRouteDiscovery.mode === "initial") {
routeDiscovery = userRouteDiscovery;
} else if (userRouteDiscovery.mode === "lazy") {View on GitHub (pinned to 6beaca3952)
Solutions
- Set an explicit positive integer, e.g. `concurrency: 4`.
- Coerce computed/env values: `concurrency: Number.parseInt(String(process.env.PRERENDER_CONCURRENCY ?? "4"), 10)` and clamp to >= 1.
- Remove the `concurrency` key to accept the default.
Example fix
// before
export default {
prerender: { concurrency: Number(process.env.PRERENDER_CONCURRENCY ?? "4.5") },
};
// after
export default {
prerender: {
concurrency: Math.max(1, Number.parseInt(String(process.env.PRERENDER_CONCURRENCY ?? "4"), 10)),
},
}; Defensive patterns
Strategy: validation
Validate before calling
function toConcurrency(raw: unknown): number | undefined {
const n = typeof raw === "number" ? raw : Number.parseInt(String(raw ?? ""), 10);
return Number.isInteger(n) && n > 0 ? n : undefined;
}
// config: prerender: { concurrency: toConcurrency(process.env.PRERENDER_CONCURRENCY) ?? 4 } Type guard
function isPositiveInteger(v: unknown): v is number {
return typeof v === "number" && Number.isInteger(v) && v > 0;
} Prevention
- Always parseInt env-derived values and clamp to >= 1.
- Avoid floating-point math when deriving worker counts (use Math.ceil/Math.round).
- If unsure, omit `concurrency` and accept the default.
When it happens
Trigger: Setting `prerender: { concurrency: 0 }` (perhaps intending 'unlimited'), a fractional value from a computed config (`Math.log2(cpus)`), or a value parsed from an env string (`process.env.CONCURRENCY` yields `"4"`, not `4`).
Common situations: Deriving concurrency from `navigator.hardwareConcurrency`-style math that yields non-integers; reading it from env vars without `parseInt`; copying a config that assumed 0 meant unlimited.
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
- The `prerender`/`prerender.paths` config must be a boolean,
- Invalid route exports found when prerendering with `ssr:fals
- The "serverBundles" function must only return strings contai
- The `prerender.unstable_concurrency` config field has been s
- The `routeDiscovery.mode` config cannot be set to "lazy" whe
AI-assisted analysis of remix-run/react-router@6beaca3952 (2026-08-18).
Data as JSON: /api/errors/37f71676a4aca388.
Report an issue: GitHub.