denoland/deno · error · Http
${error}
Error message
${error} What it means
Thrown as `new Deno.errors.Http(error)` inside the `finished` promise of an HTTP server started on an existing listener or connection (the `serveHttpOn` path used by `Deno.serveHttp(listener)` / serving over a supplied `Deno.Conn`). The serve loop awaits `op_http_wait(serverRid)`; the two benign shutdown errors (BadResource, Interrupted) are deliberately swallowed, so any other op failure is wrapped in `Deno.errors.Http` and rejects the promise stored on `server.finished`. The message is the stringified inner error, so the real cause lives in the wrapped value.
Solutions
- Catch the rejection on `server.finished` and inspect the wrapped inner error (message / `cause`) to find the real OS-level cause
- Manage lifecycle only through the returned server object (`shutdown()`, `finished`) — never close the raw `Deno.Listener`/`Deno.Conn` it was built on
- If the inner error is an OS errno (EMFILE, ECONNRESET, EBADF), check fd limits and network health
- Upgrade Deno — several wrapped-error and shutdown-path bugs have been fixed over time
Example fix
// before
const server = Deno.serveHttp(listener);
// later: unhandled rejection "Deno.errors.Http: ..."
// after
const server = Deno.serveHttp(listener);
server.finished.catch((err) => {
console.error("http server failed:", err?.cause ?? err);
Deno.exit(1);
}); Defensive patterns
Strategy: try-catch
Try / catch
try {
await server.finished;
} catch (err) {
if (err instanceof Deno.errors.Http) {
console.error("http server failed:", err.cause ?? err);
Deno.exit(1); // or restart the listener
}
throw err;
} Prevention
- Never close the raw Deno.Listener/Deno.Conn the server was built on — always go through shutdown() and finished
- Always attach a .catch() to server.finished so the rejection is observed, not reported as unhandled later
- Log err.cause, not just the wrapped Deno.errors.Http message, to see the real OS-level failure
When it happens
Trigger: Awaiting (or never awaiting) `server.finished` / the object returned by `Deno.serveHttp(listener)` when the underlying server resource fails abnormally: the OS-level listener or connection is torn down unexpectedly (fd force-closed by a supervisor, network interface drop, socket error), or an internal hyper/ops error escapes the wait op. Anything that is not a clean close becomes this wrapped error.
Common situations: Running `Deno.serveHttp` on a manually managed `Deno.Listener`/`Deno.Conn` under process supervisors or in tests that close raw resources; abrupt container/Pod network teardown; unhandled-rejection reports surfacing late because nothing awaited `server.finished`.
Related errors
- Already closed
- Already upgraded
- Deno.serve: request.signal aborts on successful responses…
- First argument to 'respondWith' must be a Response or a…
- Request closed
AI-assisted analysis of denoland/deno@abd22074e4 (2026-08-20).
Data as JSON: /api/errors/9230912a4785db71.
Report an issue: GitHub.
Appendix: source
Thrown at ext/http/00_serve.ts:1580
let ref = true;
let currentPromise = null;
// Run the server
const finished = (async () => {
const rid = context.serverRid;
try {
currentPromise = op_http_wait(rid);
if (!ref) {
core.unrefOpPromise(currentPromise);
}
await currentPromise;
currentPromise = null;
} catch (error) {
if (
!ObjectPrototypeIsPrototypeOf(BadResourcePrototype, error) &&
!ObjectPrototypeIsPrototypeOf(InterruptedPrototype, error)
) {
throw new Deno.errors.Http(error);
}
}
try {
if (!context.closing && !context.closed) {
context.closing = await op_http_close(rid, false);
context.close();
}
await context.closing;
} catch (error) {
if (ObjectPrototypeIsPrototypeOf(InterruptedPrototype, error)) {
return;
}
if (ObjectPrototypeIsPrototypeOf(BadResourcePrototype, error)) {
return;
}
View on GitHub (pinned to abd22074e4)