remix-run/react-router · error
Path ' ' requires param ' ' but it was not provided
Error message
Path '${path}' requires param '${param}' but it was not provided What it means
href() interpolates dynamic segments at runtime; any required :param (one without a trailing ?) that has no value in the params argument throws (lib/href.ts:58). With generated route types TypeScript catches this at compile time, so a runtime hit usually means the path string bypassed the typed surface (template literals, casts, or missing typegen).
Solutions
- Supply a value for every required :param in the path
- Run `react-router typegen` and keep path strings typed so the compiler catches missing params
- If the segment is genuinely optional, declare it as :param? in the route path
- Check for typos between the param name in the path string and the keys of the params object
Example fix
// before
href('/blog/:slug', {})
// after
href('/blog/:slug', { slug: post.slug }) Defensive patterns
Strategy: validation
Validate before calling
function assertParams(path: string, params: Record<string, string | undefined>) {
const required = [...path.matchAll(/\/:([\w-]+)(?!\?)/g)].map((m) => m[1]);
const missing = required.filter((p) => params[p] == null);
if (missing.length) throw new Error(`Missing params: ${missing.join(', ')}`);
}
assertParams('/users/:id/posts/:postId', params); Type guard
function hasRequiredParams(path: string, params: unknown): params is Record<string, string> {
const required = [...path.matchAll(/\/:([\w-]+)(?!\?)/g)].map((m) => m[1]);
return required.every((p) => typeof (params as any)?.[p] === 'string' && (params as any)[p] !== '');
} Try / catch
try { return href(path, params) } catch (e) { if (e instanceof Error && e.message.includes('requires param')) { return fallbackPath } throw e } Prevention
- Run `react-router typegen` in CI so untyped href calls fail the build
- Avoid `as any` on path strings; keep them literal and typed
- Unit-test dynamic href builders with all params defined
When it happens
Trigger: href('/users/:id', {}) with no id; href(path as any, params) casting away the type; param name typo like href('/blog/:slug', { id: post.id }); passing undefined/null as the params object for a path with required segments.
Common situations: Building path strings dynamically at runtime; skipping `react-router typegen` after adding routes; renaming a route param in routes.ts but not at call sites; copy-pasting href() calls from untyped examples.
Related errors
- No value found for context
- The --no-typescript flag is deprecated and will be removed…
- Unable to prerender path because it does not match any…
AI-assisted analysis of remix-run/react-router@6beaca3952 (2026-08-18).
Data as JSON: /api/errors/6586178c42b62f1a.
Report an issue: GitHub.
Appendix: source
Thrown at packages/react-router/lib/href.ts:58
* @category Utils
* @mode framework
* @param path The route path to resolve
* @param args The route params to use when resolving the path
* @returns The resolved URL path
*/
export function href<Path extends keyof Args>(
path: Path,
...args: Args[Path]
): string {
let params = args[0];
let result = trimTrailingSplat(path) // Ignore trailing / and /*, we'll handle it below
.replace(
/\/:([\w-]+)(\?)?/g, // same regex as in .\router\utils.ts: compilePath().
(_: string, param: string, questionMark: string | undefined) => {
const isRequired = questionMark === undefined;
const value = params?.[param];
if (isRequired && value === undefined) {
throw new Error(
`Path '${path}' requires param '${param}' but it was not provided`,
);
}
return value == null ? "" : "/" + encodePathParam(stringify(value));
},
);
if (path.endsWith("*")) {
// treat trailing splat the same way as compilePath, and force it to be as if it were `/*`.
// `react-router typegen` will not generate the params for a malformed splat,
// causing a type error, but we can still do the correct thing here.
const value = params?.["*"];
if (value !== undefined) {
result +=
"/" + stringify(value).split("/").map(encodePathParam).join("/");
}
}
View on GitHub (pinned to 6beaca3952)