{"record":{"id":"9175c9b3c641876d","repo":"remix-run/react-router","slug":"cannot-call-runclientmiddleware-from-within-an","errorCode":null,"errorMessage":"Cannot call `runClientMiddleware()` from within an `runClientMiddleware` handler","messagePattern":"Cannot call `runClientMiddleware\\(\\)` from within an `runClientMiddleware` handler","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/react-router/lib/router/router.ts","lineNumber":6588,"sourceCode":"  };\n  let runClientMiddleware = isStaticHandler\n    ? () => {\n        throw new Error(\n          \"You cannot call `runClientMiddleware()` from a static handler \" +\n            \"`dataStrategy`. Middleware is run outside of `dataStrategy` during \" +\n            \"SSR in order to bubble up the Response.  You can enable middleware \" +\n            \"via the `respond` API in `query`/`queryRoute`\",\n        );\n      }\n    : (cb: DataStrategyFunction<RouterContextProvider>) => {\n        let typedDataStrategyArgs =\n          dataStrategyArgs as DataStrategyFunctionArgs<RouterContextProvider>;\n        return runClientMiddlewarePipeline(typedDataStrategyArgs, () => {\n          return cb({\n            ...typedDataStrategyArgs,\n            fetcherKey,\n            runClientMiddleware: () => {\n              throw new Error(\n                \"Cannot call `runClientMiddleware()` from within an \" +\n                  \"`runClientMiddleware` handler\",\n              );\n            },\n          });\n        });\n      };\n\n  let results = await dataStrategyImpl({\n    ...dataStrategyArgs,\n    fetcherKey,\n    runClientMiddleware,\n  });\n\n  // Wait for all routes to load here but swallow the error since we want\n  // it to bubble up from the `await loadRoutePromise` in `callLoaderOrAction` -\n  // called from `match.resolve()`. We also ensure that all promises are\n  // awaited so that we don't inadvertently leave any hanging promises.","sourceCodeStart":6570,"sourceCodeEnd":6606,"githubUrl":"https://github.com/remix-run/react-router/blob/1fd704a7dabcbe3ae09d7387b460e6acaba30ec1/packages/react-router/lib/router/router.ts#L6570-L6606","documentation":"Inside the non-static `runClientMiddleware(cb)` implementation, the `cb` is invoked with a `runClientMiddleware` field that always throws. This forbids recursive nesting: a middleware handler cannot itself call `runClientMiddleware` again, which would create an unbounded pipeline.","triggerScenarios":"Calling `runClientMiddleware(...)` from within the callback passed to a previous `runClientMiddleware(...)` call inside a custom client `dataStrategy`.","commonSituations":"A dataStrategy that wraps each match with middleware and then attempts to wrap it again for a sub-pipeline; recursive helpers that 'add one more middleware layer' by calling runClientMiddleware inside the handler.","solutions":["Flatten your middleware pipeline into a single `runClientMiddleware(cb)` call per match.","If you need ordered wrappers, compose them inside `cb` directly rather than nesting `runClientMiddleware`.","Move shared logic into a plain function called from `cb`."],"exampleFix":"// before\ndataStrategy: (args) =>\n  args.runClientMiddleware((a2) =>\n    a2.runClientMiddleware(() => defaultStrategy(args)), // throws\n  ),\n\n// after\ndataStrategy: (args) =>\n  args.runClientMiddleware(() => defaultStrategy(args)),","handlingStrategy":"validation","validationCode":"let depth = 0;\nconst safeRunClientMiddleware = (cb) => {\n  if (++depth > 1) throw new Error('nested runClientMiddleware');\n  try { return runClientMiddleware(cb); } finally { depth--; }\n};","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Call `runClientMiddleware` at most once per match.","Compose ordered middleware inside the callback rather than nesting."],"tags":["middleware","data-strategy","recursion","client"],"backgroundTag":null,"analyzedSha":"1fd704a7dabcbe3ae09d7387b460e6acaba30ec1","analyzedAt":"2026-08-12T13:54:57.804Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}