{"record":{"id":"6942dbfd212a1f24","repo":"denoland/deno","slug":"err-server-already-listen","errorCode":"ERR_SERVER_ALREADY_LISTEN","errorMessage":"Listen method has been called more than once without closing.","messagePattern":"Listen method has been called more than once without closing\\.","errorType":"error_code","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"ext/node/polyfills/net.ts","lineNumber":2915,"sourceCode":" * details).\n *\n * The `server.listen()` method can be called again if and only if there was an\n * error during the first `server.listen()` call or `server.close()` has been\n * called. Otherwise, an `ERR_SERVER_ALREADY_LISTEN` error will be thrown.\n *\n * One of the most common errors raised when listening is `EADDRINUSE`.\n * This happens when another server is already listening on the requested`port`/`path`/`handle`. One way to handle this would be to retry\n * after a certain amount of time:\n */\nServer.prototype.listen = function (...args: unknown[]) {\n  const normalized = _normalizeArgs(args);\n  let options = normalized[0] as Partial<ListenOptions>;\n  const cb = normalized[1];\n\n  this._listeningId++;\n\n  if (this._handle) {\n    throw new ERR_SERVER_ALREADY_LISTEN();\n  }\n\n  if (cb !== null) {\n    this.once(\"listening\", cb);\n  }\n\n  // The 'net.server.listen' tracingChannel publishes the user-visible\n  // listen() options. Doing it here (after _normalizeArgs but before any\n  // pre-existing-handle short-circuits return) lets subscribers see the same\n  // options the caller passed in (including ad-hoc fields like\n  // `customOption` used by test-diagnostics-channel-net to verify the\n  // payload is the original options object).\n  if (netServerListenChannel.hasSubscribers) {\n    netServerListenChannel.asyncStart.publish({ server: this, options });\n  }\n\n  const backlogFromArgs: number =\n    // (handle, backlog) or (path, backlog) or (port, backlog)","sourceCodeStart":2897,"sourceCodeEnd":2933,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/node/polyfills/net.ts#L2897-L2933","documentation":"`server.listen()` throws ERR_SERVER_ALREADY_LISTEN when the server already holds a handle from a previous listen that was never closed. The check is `this._handle`, so even a listen that has not finished binding counts as active. One listen per server instance is allowed.","triggerScenarios":"Calling `listen()` twice on the same server. A retry handler that calls `listen()` again from inside the first attempt's error or restart path. Hot-reload or test setups that reuse a module-level server without closing it.","commonSituations":"EADDRINUSE retry logic that re-calls listen immediately. Rebinding a server to another port at runtime without teardown. Tests that share one server across cases and call listen in each.","solutions":["Call `server.close()` and wait for the 'close' event before calling `listen()` again.","Guard with `if (server.listening) return;` before listen.","Create a new `net.Server` instance when the old one may still be bound.","In retry loops, schedule the retry from the close callback, not from the error handler."],"exampleFix":"// before\nserver.listen(port);\nserver.listen(port + 1); // throws ERR_SERVER_ALREADY_LISTEN\n\n// after\nserver.listen(port);\nserver.close(() => server.listen(port + 1));","handlingStrategy":"validation","validationCode":"async function safeListen(server, ...args) {\n  if (server.listening) {\n    await new Promise((resolve) => server.close(resolve));\n  }\n  return server.listen(...args);\n}","typeGuard":null,"tryCatchPattern":"try {\n  server.listen(port);\n} catch (err) {\n  if (err?.code === 'ERR_SERVER_ALREADY_LISTEN') {\n    server.close(() => server.listen(port)); // re-listen from the close callback\n  } else throw err;\n}","preventionTips":["Check server.listening before every listen call.","Wait for the 'close' event before rebinding; the close callback is the only safe re-listen point.","In tests, create a fresh server per case or close in afterEach.","In EADDRINUSE retries, add backoff and re-listen from close, not from the error handler."],"tags":["net","server","listen","lifecycle","eaddrinuse-retry"],"backgroundTag":"server-already-listening","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}