remix-run/react-router · error
Cannot call `runClientMiddleware()` from within an…
Error message
Cannot call `runClientMiddleware()` from within an `runClientMiddleware` handler
What it means
The callback you pass to runClientMiddleware(cb) receives args whose runClientMiddleware is intentionally a throwing stub (lib/router/router.ts:6588): nesting is disallowed because the outer call is already driving the middleware pipeline for this request/fetcher scope.
Solutions
- Flatten the logic: make a single runClientMiddleware call at the top of your dataStrategy
- Move shared inner work into plain functions that take args, not into another middleware pipeline
- Delete the nested wrapper call and reuse the result of the single outer call
Example fix
// before
args.runClientMiddleware(async (a) => {
return a.runClientMiddleware(async () => doWork(a)) // throws
})
// after
args.runClientMiddleware(async (a) => doWork(a)) Defensive patterns
Strategy: validation
Validate before calling
// Structural rule: call runClientMiddleware once per (request, fetcherKey) scope
let wrapped = false;
const dataStrategy = async (args) => {
if (!wrapped) { wrapped = true; return args.runClientMiddleware(() => doWork(args)) }
return doWork(args);
}; Prevention
- Make exactly one runClientMiddleware call at the top of your dataStrategy
- Factor inner layers into plain functions receiving args instead of nested pipelines
- Review wrappers (tracing/auth) applied at multiple layers of the same call tree
When it happens
Trigger: Inside args.runClientMiddleware(async (ctx) => { ... }), calling ctx.runClientMiddleware(...) (or the outer one captured earlier) again for a nested fetch; recursive helper functions that wrap each level in runClientMiddleware.
Common situations: Composing several middleware-wrapped operations in one dataStrategy; generic wrappers (tracing, auth refresh) applied at multiple layers of the same call tree.
Related errors
- You cannot call `runClientMiddleware()` from a static…
- No value found for context
- You may only call `next()` once per middleware
- Failed to clone server response
- Missing body in server response
AI-assisted analysis of remix-run/react-router@7aea711dd1 (2026-08-18).
Data as JSON: /api/errors/9175c9b3c641876d.
Report an issue: GitHub.
Appendix: source
Thrown at packages/react-router/lib/router/router.ts:6567
};
let runClientMiddleware = isStaticHandler
? () => {
throw new Error(
"You cannot call `runClientMiddleware()` from a static handler " +
"`dataStrategy`. Middleware is run outside of `dataStrategy` during " +
"SSR in order to bubble up the Response. You can enable middleware " +
"via the `respond` API in `query`/`queryRoute`",
);
}
: (cb: DataStrategyFunction<RouterContextProvider>) => {
let typedDataStrategyArgs =
dataStrategyArgs as DataStrategyFunctionArgs<RouterContextProvider>;
return runClientMiddlewarePipeline(typedDataStrategyArgs, () => {
return cb({
...typedDataStrategyArgs,
fetcherKey,
runClientMiddleware: () => {
throw new Error(
"Cannot call `runClientMiddleware()` from within an " +
"`runClientMiddleware` handler",
);
},
});
});
};
let results = await dataStrategyImpl({
...dataStrategyArgs,
fetcherKey,
runClientMiddleware,
});
// Wait for all routes to load here but swallow the error since we want
// it to bubble up from the `await loadRoutePromise` in `callLoaderOrAction` -
// called from `match.resolve()`. We also ensure that all promises are
// awaited so that we don't inadvertently leave any hanging promises.View on GitHub (pinned to 7aea711dd1)