{"record":{"id":"2e24c7c60fa4a6ce","repo":"honojs/hono","slug":"forbidden-2e24c7","errorCode":null,"errorMessage":"Forbidden","messagePattern":"Forbidden","errorType":"http","errorClass":"HTTPException","httpStatus":403,"severity":"error","filePath":"src/middleware/ip-restriction/index.ts","lineNumber":242,"sourceCode":"  ) => Response | Promise<Response>\n): MiddlewareHandler => {\n  const allowLength = allowList.length\n\n  const denyMatcher = buildMatcher(denyList)\n  const allowMatcher = buildMatcher(allowList)\n\n  const blockError = (c: Context): HTTPException =>\n    new HTTPException(403, {\n      res: c.text('Forbidden', {\n        status: 403,\n      }),\n    })\n\n  return async function ipRestriction(c, next) {\n    const connInfo = getIP(c)\n    const addr = typeof connInfo === 'string' ? connInfo : connInfo.remote.address\n    if (!addr) {\n      throw blockError(c)\n    }\n    const type =\n      (typeof connInfo !== 'string' && connInfo.remote.addressType) || distinctRemoteAddr(addr)\n\n    const remoteData = { addr, type, isIPv4: type === 'IPv4' }\n\n    try {\n      if (denyMatcher(remoteData)) {\n        if (onError) {\n          return onError({ addr, type }, c)\n        }\n        throw blockError(c)\n      }\n      if (allowMatcher(remoteData)) {\n        return await next()\n      }\n    } catch (e) {\n      if (","sourceCodeStart":224,"sourceCodeEnd":260,"githubUrl":"https://github.com/honojs/hono/blob/e2740d5a1bd0b4254e517e3af8b60789284bc7bd/src/middleware/ip-restriction/index.ts#L224-L260","documentation":"Hono's ipRestriction middleware throws a 403 Forbidden error (via blockError) when it cannot determine the client's IP address. The middleware reads connection info (getIP(c)) and if no remote address is resolvable, it fails closed and blocks the request rather than allowing an unidentified client through.","triggerScenarios":"Using secureHeaders/ipRestriction middleware where connInfo is undefined or connInfo.remote.address is missing — e.g. running under a runtime or adapter that doesn't provide Hono's conninfo helper (plain Node server without getConnectionInfo, Bun, some edge runtimes), or testing with app.request() where no socket exists.","commonSituations":"Adding IP restrictions in local dev where req.raw has no connection info; deploying behind a proxy that strips connection data; forgetting to wire an app.getConnectionHelper or use the correct runtime adapter that populates conninfo.","solutions":["Ensure the runtime adapter provides connection info (e.g. serve({ fetch: app.fetch, port }, (info) => ({ remote: info })) for @hono/node-server / Bun)","Test IP restriction with a real HTTP request instead of app.request()","If behind a trusted proxy, configure getIP to read a forwarded header like x-forwarded-for so an address is always resolvable"],"exampleFix":"// before\nconst app = new Hono()\napp.use(ipRestriction(getIPs /* no conninfo configured */))\n\n// after (Node.js)\nimport { serve } from '@hono/node-server'\nserve({ fetch: app.fetch, port: 3000 }, (info) => ({ remote: info }))","handlingStrategy":"validation","validationCode":"const getConnIP = (c: Context): string | undefined => {\n  try {\n    const info = c.env?.conninfo ?? getIP(c)\n    return typeof info === 'string' ? info : info?.remote?.address\n  } catch {\n    return undefined\n  }\n}","typeGuard":null,"tryCatchPattern":"app.onError((err, c) => {\n  if (err instanceof HTTPException && err.status === 403) {\n    return c.text('Access denied', 403)\n  }\n  throw err\n})","preventionTips":["Configure the server adapter to supply conninfo (serve options callback)","Test IP middleware with real HTTP requests, not app.request()","Behind a proxy, derive the IP from x-forwarded-for in getIP"],"tags":["hono","ip-restriction","middleware","conninfo","forbidden"],"backgroundTag":"ip-restriction-blocked","analyzedSha":"e2740d5a1bd0b4254e517e3af8b60789284bc7bd","analyzedAt":"2026-08-28T10:18:08.750Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}