remix-run/react-router · error · Error
Path '${path}' requires param '${param}' but it was not prov
Error message
Path '${path}' requires param '${param}' but it was not provided What it means
`href()` interpolates `/param` segments of a route path string. A required segment (`:name` with no trailing `?`) had no value in the `params` argument, so it cannot be filled in. This is the runtime counterpart of a check that `react-router typegen` performs at compile time.
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 1fd704a7da)
Solutions
- Provide a value for every required `:param` in the params object.
- If the param should be optional, declare the route segment as `:param?`.
- Regenerate types (`pnpm run typegen`) so TypeScript catches missing params at compile time.
- Audit every `href()` call site for the route after changing its param shape.
Example fix
// before
href('/users/:userId/posts/:postId', { userId: '1' });
// after
href('/users/:userId/posts/:postId', { userId: '1', postId: '42' }); Defensive patterns
Strategy: validation
Validate before calling
function hasAllRequiredParams(path: string, params: Record<string, unknown>): boolean {
const required = (path.match(/\/:([\w-]+)(?!\?)/g) ?? []).map((m) => m.slice(2));
return required.every((p) => params[p] != null);
}
if (!hasAllRequiredParams(path, params)) throw new Error('Missing required params'); Type guard
function isCompleteParams(path: string, params: Record<string, unknown>): params is Record<string, string> {
const required = (path.match(/\/:([\w-]+)(?!\?)/g) ?? []).map((m) => m.slice(2));
return required.every((p) => typeof params[p] === 'string' && params[p].length > 0);
} Prevention
- Regenerate types after every route-shape change.
- Don't cast params to `any`; let the generated `href` overloads type-check args.
- Centralize route path strings as typed constants.
When it happens
Trigger: Calling `href('/users/:userId/posts/:postId', { userId: '1' })` where `:postId` is required but omitted; passing `undefined` for a required param; a refactor that adds a new required param to a route but not all `href()` call sites are updated.
Common situations: Dynamic routes whose params change during development; passing `params` from a loosely-typed source (search params, JSON) that omits a key; bypassing TypeScript by casting `params as any`.
Related errors
- Unable to define routes with duplicate route id: "${id}"
- No handlers were found for the request: ${url.pathname}${url
- Unable to prerender path because it does not match any route
- Unable to define routes with duplicate route id: "${route.id
AI-assisted analysis of remix-run/react-router@1fd704a7da (2026-08-12).
Data as JSON: /api/errors/6586178c42b62f1a.
Report an issue: GitHub.