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

  1. Catch the rejection on `server.finished` and inspect the wrapped inner error (message / `cause`) to find the real OS-level cause
  2. Manage lifecycle only through the returned server object (`shutdown()`, `finished`) — never close the raw `Deno.Listener`/`Deno.Conn` it was built on
  3. If the inner error is an OS errno (EMFILE, ECONNRESET, EBADF), check fd limits and network health
  4. 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

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


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)