{"record":{"id":"c12435333278e771","repo":"denoland/deno","slug":"cannot-read-url-request-closed-c12435","errorCode":null,"errorMessage":"Cannot read url: request closed","messagePattern":"Cannot read url: request closed","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/fetch/23_request.js","lineNumber":177,"sourceCode":"    clientRid: null,\n    blobUrlEntry,\n    url() {\n      if (this.urlListProcessed[0] === undefined) {\n        try {\n          this.urlListProcessed[0] = this.urlList[0]();\n        } catch {\n          throw new TypeError(\"cannot read url: request closed\");\n        }\n      }\n      return this.urlListProcessed[0];\n    },\n    currentUrl() {\n      const currentIndex = this.urlList.length - 1;\n      if (this.urlListProcessed[currentIndex] === undefined) {\n        try {\n          this.urlListProcessed[currentIndex] = this.urlList[currentIndex]();\n        } catch {\n          throw new TypeError(\"Cannot read url: request closed\");\n        }\n      }\n      return this.urlListProcessed[currentIndex];\n    },\n  };\n}\n\n/**\n * https://fetch.spec.whatwg.org/#concept-request-clone\n * @param {InnerRequest} request\n * @param {boolean} skipBody\n * @returns {InnerRequest}\n */\nfunction cloneInnerRequest(request, skipBody = false) {\n  const headerList = ArrayPrototypeMap(\n    request.headerList,\n    (x) => [x[0], x[1]],\n  );","sourceCodeStart":159,"sourceCodeEnd":195,"githubUrl":"https://github.com/denoland/deno/blob/89f33cbef296a2b287f323d42de54c871fa69c77/ext/fetch/23_request.js#L159-L195","documentation":"InnerRequest.currentUrl() resolves the LAST entry of urlList (the URL after redirects) lazily via the urlList[currentIndex]() closure. If that underlying source is closed, the call throws and is converted to TypeError 'Cannot read url: request closed' (capital C, matching currentUrl()). Distinct from error 84 only in which accessor and list index is involved.","triggerScenarios":"Calling request.currentUrl() (used internally after redirect chains) on an op-backed request whose resource closed before the currentUrl getter could cache urlListProcessed[currentIndex].","commonSituations":"Redirect handling or response URL reporting that runs after the originating connection/resource was reaped; deferred logging of final URLs for followed redirects.","solutions":["Materialize the current/final URL while the request resource is still open (right after fetch resolves)","Snapshot response.url and other derived strings instead of re-deriving them later from the request","Tie request processing to request.signal so work stops when the connection closes"],"exampleFix":"// before\nconst job = fetch('https://example.com/a') // redirects\n  .then((res) => ({ get url() { return res.url; /* late access may hit closed source */ } }));\n\n// after\nconst job = fetch('https://example.com/a').then((res) => {\n  const url = res.url; // capture eagerly\n  return { url };\n});","handlingStrategy":"try-catch","validationCode":"const finalUrl = (() => {\n  try {\n    return response.url; // materialize final (post-redirect) URL now\n  } catch {\n    return null;\n  }\n})();","typeGuard":null,"tryCatchPattern":"try {\n  report(req.currentUrl()); // or response.url\n} catch (err) {\n  if (err instanceof TypeError && err.message === 'Cannot read url: request closed') return; // source gone, skip\n  throw err;\n}","preventionTips":["Capture response.url as a string the moment fetch resolves","Do not re-derive final URLs from request objects later in async flows","Bind analytics/reporting to the Response snapshot, not the live request"],"tags":["fetch","request","redirect","lifecycle"],"backgroundTag":null,"analyzedSha":"89f33cbef296a2b287f323d42de54c871fa69c77","analyzedAt":"2026-08-16T07:54:21.310Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}