garrytan/gstack · error · Error
socks-bridge: unexpected listener address
Error message
socks-bridge: unexpected listener address
What it means
Invariant thrown by the SOCKS bridge in socks-bridge.ts immediately after `listening` fires. Node's `server.address()` must return an AddressInfo object for a TCP listener; this branch catches the unexpected cases (null after close, or a string for Unix-socket/IPC bindings) before the caller reads `address.port`.
Source
Thrown at browse/src/socks-bridge.ts:231
return;
}
};
clientSocket.on('data', onData);
clientSocket.on('error', () => killBoth('client error'));
});
await new Promise<void>((resolve, reject) => {
const onErr = (e: unknown) => { server.off('listening', onListen); reject(e); };
const onListen = () => { server.off('error', onErr); resolve(); };
server.once('error', onErr);
server.once('listening', onListen);
server.listen(requestedPort, '127.0.0.1');
});
const address = server.address();
if (!address || typeof address === 'string') {
throw new Error('socks-bridge: unexpected listener address');
}
return {
port: address.port,
server,
close: async () => {
for (const sock of inFlight) {
try { sock.destroy(); } catch { /* already gone */ }
}
inFlight.clear();
await new Promise<void>((resolve) => server.close(() => resolve()));
},
};
}
export interface UpstreamTestOpts {
upstream: UpstreamConfig;
/** Hostname to test connectivity to through the upstream. Default 1.1.1.1. */View on GitHub (pinned to 94993f7401)
Solutions
- Do not call `close()` on the returned bridge object before the `startSocksBridge()` promise resolves.
- Confirm you are binding a TCP socket — the bridge always calls `server.listen(port, '127.0.0.1')`, so any IPC path injection in a fork would cause this.
- If you see this in production, capture a core dump at the throw site — it indicates a race that should not happen in normal flow.
- Update to the latest browse version; this guard exists to fail fast rather than return a port of `undefined`.
Defensive patterns
Strategy: try-catch
Type guard
import type { AddressInfo } from 'net';
function isAddressInfo(a: any): a is AddressInfo {
return !!a && typeof a === 'object' && typeof a.port === 'number';
} Try / catch
try {
const bridge = await startSocksBridge({ ... });
return bridge;
} catch (e: any) {
if (/socks-bridge: unexpected listener address/.test(e.message)) {
// listener closed during bind — retry once with a fresh server
return startSocksBridge({ ... });
}
throw e;
} Prevention
- Never call bridge.close() before startSocksBridge resolves.
- Treat this throw as a bug report — it should not occur in normal flow.
- Pin to a known-good browse version; the guard was added to fail fast on a real race.
- If you fork the bridge, keep the TCP listener — do not switch to IPC paths.
When it happens
Trigger: The listener was closed between the `listening` event and the synchronous `address()` call; the server was misconfigured to bind a Unix socket/IPC path instead of a TCP port; an internal race where `server.close()` runs in the same tick as `listening`.
Common situations: A custom embedder that closes the bridge inside the listen promise; passing a string option where the address family expects TCP; running under a supervisor that signals SIGTERM during bind.
AI-assisted analysis of garrytan/gstack@94993f7401 (2026-08-12).
Data as JSON: /api/errors/e6149adc20b1f0e4.
Report an issue: GitHub.