{"record":{"id":"6b028babeb26757d","repo":"honojs/hono","slug":"next-called-multiple-times","errorCode":null,"errorMessage":"next() called multiple times","messagePattern":"next\\(\\) called multiple times","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/compose.ts","lineNumber":34,"sourceCode":"  middleware: [[Function, unknown], unknown][] | [[Function]][],\n  onError?: ErrorHandler<E>,\n  onNotFound?: NotFoundHandler<E>\n): ((context: Context, next?: Next) => Promise<Context>) => {\n  return (context, next) => {\n    let index = -1\n\n    return dispatch(0)\n\n    /**\n     * Dispatch the middleware functions.\n     *\n     * @param {number} i - The current index in the middleware array.\n     *\n     * @returns {Promise<Context>} - A promise that resolves to the context.\n     */\n    async function dispatch(i: number): Promise<Context> {\n      if (i <= index) {\n        throw new Error('next() called multiple times')\n      }\n      index = i\n\n      let res\n      let isError = false\n      let handler\n\n      if (middleware[i]) {\n        handler = middleware[i][0][0]\n        context.req.routeIndex = i\n      } else {\n        handler = (i === middleware.length && next) || undefined\n      }\n\n      if (handler) {\n        try {\n          res = await handler(context, () => dispatch(i + 1))\n        } catch (err) {","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/honojs/hono/blob/e2740d5a1bd0b4254e517e3af8b60789284bc7bd/src/compose.ts#L16-L52","documentation":"Hono's compose() guards against middleware calling `next()` more than once per invocation. Each middleware gets a one-shot next(); dispatch tracks the current index and throws if a later dispatch has an index not greater than the last — which happens when a single execution path awaits next() twice, or two branches of the same middleware both call next().","triggerScenarios":"Calling `await next()` twice in one middleware body (including in both a try and a catch/finally path that both run), calling next() without await and then calling it again, or recursive/branching code inside a handler that reaches multiple next() calls for one request.","commonSituations":"Copy-pasted middleware that calls next() in both try and catch; race conditions where a timeout branch also calls next(); refactors that accidentally leave a stray next() call; conditional code paths that both execute (e.g. next() inside if and after the if).","solutions":["Search the failing middleware for every `next()` call and ensure exactly one executes per request","Don't call next() in finally or in both try/catch branches; call it once before other logic","Return or branch after calling next(): `await next(); return c.text(...)`","Reproduce with a log/marker in each middleware to identify which one double-calls"],"exampleFix":"// before\napp.use(async (c, next) => {\n  try {\n    await next()\n  } catch {\n    await next() // second call -> 'next() called multiple times'\n  }\n})\n\n// after\napp.use(async (c, next) => {\n  try {\n    await next()\n  } catch (err) {\n    // handle error; do NOT call next() again\n  }\n})","handlingStrategy":"validation","validationCode":"app.use(async (c, next) => {\n  let called = false\n  const once = () => {\n    if (called) throw new Error('next() called multiple times')\n    called = true\n    return next()\n  }\n  // pass `once` instead of next to downstream logic\n})","typeGuard":null,"tryCatchPattern":"try { await handler(c, next) } catch (e) { if (e instanceof Error && e.message === 'next() called multiple times') { /* fix the middleware that double-calls next */ } throw e }","preventionTips":["Call next() exactly once per middleware; never in finally","grep every custom middleware for 'next(' and count call sites","Return immediately after awaiting next() when handling post-logic"],"tags":["middleware","compose","next","double-call","control-flow"],"backgroundTag":"middleware-next-called-twice","analyzedSha":"e2740d5a1bd0b4254e517e3af8b60789284bc7bd","analyzedAt":"2026-08-28T10:18:08.750Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}