denoland/deno · error · Error

ERR_HTTP2_SOCKET_UNBOUND

ERR_HTTP2_SOCKET_UNBOUND

Error message

The socket has been disconnected from the Http2Session

What it means

The Http2Session socket proxy's get trap allows a passthrough for properties not on the banned list, but only if session[kSocket] is still bound. Once the session is destroyed/closed the socket is detached, and reading any non-banned property (remoteAddress, writable, etc.) throws ERR_HTTP2_SOCKET_UNBOUND: 'The socket has been disconnected from the Http2Session'.

Source

Thrown at ext/node/polyfills/http2.ts:811

      case "setTimeout":
      case "ref":
      case "unref":
        return FunctionPrototypeBind(session[prop], session);
      case "destroy":
      case "emit":
      case "end":
      case "pause":
      case "read":
      case "resume":
      case "write":
      case "setEncoding":
      case "setKeepAlive":
      case "setNoDelay":
        throw new ERR_HTTP2_NO_SOCKET_MANIPULATION();
      default: {
        const socket = session[kSocket];
        if (socket === undefined) {
          throw new ERR_HTTP2_SOCKET_UNBOUND();
        }
        const value = socket[prop];
        return typeof value === "function"
          ? FunctionPrototypeBind(value, socket)
          : value;
      }
    }
  },
  getPrototypeOf(session) {
    const socket = session[kSocket];
    if (socket === undefined) {
      throw new ERR_HTTP2_SOCKET_UNBOUND();
    }
    return ReflectGetPrototypeOf(socket);
  },
  set(session, prop, value) {
    switch (prop) {
      case "setTimeout":

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Guard with if (!session.destroyed && !session.closed) before reading session.socket properties
  2. Capture the peer details (remoteAddress, remotePort) once, early in the session lifetime, and reuse the snapshot
  3. Register 'close' listeners that stop referencing session.socket rather than reading it

Example fix

// before
session.on('close', () => {
  log(session.socket.remoteAddress); // throws ERR_HTTP2_SOCKET_UNBOUND
});

// after
const peer = session.socket.remoteAddress; // captured while bound
session.on('close', () => log(peer));
Defensive patterns

Strategy: validation

Validate before calling

const socketInfo = (session: Http2Session) =>
  session.destroyed || session.closed
    ? undefined
    : { addr: session.socket.remoteAddress, port: session.socket.remotePort };

Type guard

const hasBoundSocket = (session: Http2Session): boolean =>
  !session.destroyed && !session.closed;

Try / catch

try {
  log(session.socket.remoteAddress);
} catch (err) {
  if ((err as NodeJS.ErrnoException).code === 'ERR_HTTP2_SOCKET_UNBOUND') {
    // session already tore down; use a snapshot captured earlier
  } else throw err;
}

Prevention

When it happens

Trigger: Reading session.socket.remoteAddress / remotePort / encrypted in a 'close' or shutdown handler; logging socket details inside an error handler that runs after session.destroy(); accessing session.socket properties after a GOAWAY or fatal error unbound the socket.

Common situations: Access-log or audit middleware that inspects the peer address at request end, which can race session teardown; graceful-shutdown code that iterates sessions and inspects sockets after closing them; error reporters digging into socket state post-mortem.

Related errors


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/9a0636d6718bf6ff. Report an issue: GitHub.