denoland/deno · error · TypeError

Request closed

Error message

Request closed

What it means

The internal serve request object caches its URL lazily from the native handle. Once the request is finalized and the native handle released (#external === null), calling url() throws a TypeError ('Request closed'). Practically: reading the request URL after the response has completed touches a dead resource.

Solutions

  1. Read request.url (and any other request data) synchronously at handler entry and capture it into a local
  2. Pass plain copied values (url string, method, headers snapshot) to async/background work instead of the Request object
  3. Move post-response logging into code that already holds the captured values, not the request

Example fix

// before
Deno.serve((req) => {
  queueMicrotask(() => log(req.url)); // may run after close -> TypeError
  return new Response("ok");
});

// after
Deno.serve((req) => {
  const url = req.url; // capture synchronously
  queueMicrotask(() => log(url));
  return new Response("ok");
});
Defensive patterns

Strategy: validation

Validate before calling

Deno.serve((req) => {
  const ctx = {
    url: req.url,               // capture synchronously
    method: req.method,
    headers: [...req.headers],  // snapshot
  };
  scheduleBackgroundLog(ctx);   // safe: only uses the snapshot
  return handle(ctx, req);
});

Try / catch

try {
  log(req.url);
} catch (err) {
  if (err instanceof TypeError && err.message === "Request closed") {
    // too late: fall back to a previously captured value
  } else throw err;
}

Prevention

When it happens

Trigger: Accessing the request's URL in a detached task (fire-and-forget promise) after the handler returned; logging or metrics code that reads request.url after await respondWith(...); accessing a stored request object in a queue processed after the response finished.

Common situations: Access logs written in background flushers; request objects captured in closures and inspected later; spans/traces closed asynchronously after the response.

Related errors


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

Appendix: source

Thrown at ext/http/00_serve.ts:271

      this.url();
      this.headerList;
      this.remoteAddr;
      this.close();

      this.#upgraded = true;

      return op_http_upgrade_websocket_next(external);
    }
  }

  url() {
    if (this.#urlValue !== undefined) {
      return this.#urlValue;
    }

    if (this.#external === null) {
      throw new TypeError("Request closed");
    }

    if (this.#methodValue === undefined) {
      this.#methodValue = op_http_get_request_method(this.#external);
    }

    return this.#urlValue = op_http_get_request_url(this.#external);
  }

  get completed() {
    if (!this.#completed) {
      // NOTE: this is faster than Promise.withResolvers()
      let resolve, reject;
      const promise = new Promise((r1, r2) => {
        resolve = r1;
        reject = r2;
      });
      this.#completed = { promise, resolve, reject };

View on GitHub (pinned to abd22074e4)