<p dir="auto">Take the following examples:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="async function doRequest() {
    const res = await fetch(&quot;http://localhost:4545/cli/tests/fixture.json&quot;);

    const someCondition = true;
    if (someCondition) throw new Error();

    const body = await res.json();

    return body;
}

doRequest().catch(console.error);

setInterval(() =&gt; {
    console.log(Deno.resources());
}, 2000);"><pre class="notranslate"><code class="notranslate">async function doRequest() {
    const res = await fetch("http://localhost:4545/cli/tests/fixture.json");

    const someCondition = true;
    if (someCondition) throw new Error();

    const body = await res.json();

    return body;
}

doRequest().catch(console.error);

setInterval(() =&gt; {
    console.log(Deno.resources());
}, 2000);
</code></pre></div>
<hr>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content=" await fetch(&quot;http://localhost:4545/cli/tests/fixture.json&quot;);
// I don't care about the body"><pre class="notranslate"><code class="notranslate"> await fetch("http://localhost:4545/cli/tests/fixture.json");
// I don't care about the body
</code></pre></div>
<p dir="auto">Since fetch response resource id is only closed after the body is consumed, in the examples above the resource handle for both requests are never closed. Easily reproducible in a test.</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="Deno.test('leak', async() =&gt; {
         await fetch(&quot;http://localhost:4545/cli/tests/fixture.json&quot;);
        // I don't care about the body
});"><pre class="notranslate"><code class="notranslate">Deno.test('leak', async() =&gt; {
         await fetch("http://localhost:4545/cli/tests/fixture.json");
        // I don't care about the body
});
</code></pre></div>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="AssertionError: Test case is leaking resources.
Before: {
  &quot;0&quot;: &quot;stdin&quot;,
  &quot;1&quot;: &quot;stdout&quot;,
  &quot;2&quot;: &quot;stderr&quot;
}
After: {
  &quot;0&quot;: &quot;stdin&quot;,
  &quot;1&quot;: &quot;stdout&quot;,
  &quot;2&quot;: &quot;stderr&quot;,
  &quot;3&quot;: &quot;httpBody&quot;
}"><pre class="notranslate"><code class="notranslate">AssertionError: Test case is leaking resources.
Before: {
  "0": "stdin",
  "1": "stdout",
  "2": "stderr"
}
After: {
  "0": "stdin",
  "1": "stdout",
  "2": "stderr",
  "3": "httpBody"
}
</code></pre></div>
<p dir="auto">Currently, there's no way in Deno to close the resource handle without consuming the body.<br>
Fetch specification does not mention anything about a default read timeout, where we could close the handle after the timeout is reached.</p>
<p dir="auto">Fortunately, it provides a way to abort the request &amp; consumption of the body using <code class="notranslate">AbortController</code>, and <code class="notranslate">signal</code> option (not supported in Deno).</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content=" const abort = new AbortController();
 const res = await fetch(&quot;http://localhost:4545/cli/tests/fixture.json&quot;, {
   signal: abort.signal,
 });
 assert(res.ok);
// Discard body
 abort.abort();"><pre class="notranslate"><code class="notranslate"> const abort = new AbortController();
 const res = await fetch("http://localhost:4545/cli/tests/fixture.json", {
   signal: abort.signal,
 });
 assert(res.ok);
// Discard body
 abort.abort();
</code></pre></div>
<p dir="auto">Until the above is supported fetch response body must always be consumed.</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="const res = await fetch(&quot;http://localhost:4545/cli/tests/fixture.json&quot;);
await res.text(); // consume body"><pre class="notranslate"><code class="notranslate">const res = await fetch("http://localhost:4545/cli/tests/fixture.json");
await res.text(); // consume body
</code></pre></div>
<p dir="auto">Hi <g-emoji class="g-emoji" alias="wave" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f44b.png">👋</g-emoji><br>
I believe I have found an issue where the <code class="notranslate">fetch</code>-api leaks resources if the<br>
body is not resolved, e.g. with <code class="notranslate">.text()</code>/<code class="notranslate">.json()</code>.</p>
<p dir="auto">Given the following test:</p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="import { assertEquals } from &quot;https://deno.land/std/testing/asserts.ts&quot;;

Deno.test(&quot;fetching TODOs&quot;, async () =&gt; {

        const response = await fetch(&quot;https://jsonplaceholder.typicode.com/todos/&quot;);
        //await response.json(); //NOTE: adding this line removes the issue (or .text()/similar)
        assertEquals(200, response.status);
});"><pre class="notranslate"><span class="pl-k">import</span> <span class="pl-kos">{</span> <span class="pl-s1">assertEquals</span> <span class="pl-kos">}</span> <span class="pl-k">from</span> <span class="pl-s">"https://deno.land/std/testing/asserts.ts"</span><span class="pl-kos">;</span>

<span class="pl-smi">Deno</span><span class="pl-kos">.</span><span class="pl-en">test</span><span class="pl-kos">(</span><span class="pl-s">"fetching TODOs"</span><span class="pl-kos">,</span> <span class="pl-k">async</span> <span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-kos">{</span>

        <span class="pl-k">const</span> <span class="pl-s1">response</span> <span class="pl-c1">=</span> <span class="pl-k">await</span> <span class="pl-en">fetch</span><span class="pl-kos">(</span><span class="pl-s">"https://jsonplaceholder.typicode.com/todos/"</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
        <span class="pl-c">//await response.json(); //NOTE: adding this line removes the issue (or .text()/similar)</span>
        <span class="pl-en">assertEquals</span><span class="pl-kos">(</span><span class="pl-c1">200</span><span class="pl-kos">,</span> <span class="pl-s1">response</span><span class="pl-kos">.</span><span class="pl-c1">status</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span><span class="pl-kos">)</span><span class="pl-kos">;</span></pre></div>
<p dir="auto">Produces the following output:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="running 1 tests
test fetching TODOs ... FAILED (94ms)

failures:

fetching TODOs
Error: Test case is leaking resources.
Before: {
  &quot;0&quot;: &quot;stdin&quot;,
  &quot;1&quot;: &quot;stdout&quot;,
  &quot;2&quot;: &quot;stderr&quot;
}
After: {
  &quot;0&quot;: &quot;stdin&quot;,
  &quot;1&quot;: &quot;stdout&quot;,
  &quot;2&quot;: &quot;stderr&quot;,
  &quot;3&quot;: &quot;httpBody&quot;
}
    at Object.assert ($deno$/util.ts:25:11)
    at Object.resourceSanitizer [as fn] ($deno$/testing.ts:75:5)
    at async TestApi.[Symbol.asyncIterator] ($deno$/testing.ts:259:11)
    at async Object.runTests ($deno$/testing.ts:341:20)

failures:

	fetching TODOs

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out (95ms)"><pre class="notranslate"><code class="notranslate">running 1 tests
test fetching TODOs ... FAILED (94ms)

failures:

fetching TODOs
Error: Test case is leaking resources.
Before: {
  "0": "stdin",
  "1": "stdout",
  "2": "stderr"
}
After: {
  "0": "stdin",
  "1": "stdout",
  "2": "stderr",
  "3": "httpBody"
}
    at Object.assert ($deno$/util.ts:25:11)
    at Object.resourceSanitizer [as fn] ($deno$/testing.ts:75:5)
    at async TestApi.[Symbol.asyncIterator] ($deno$/testing.ts:259:11)
    at async Object.runTests ($deno$/testing.ts:341:20)

failures:

	fetching TODOs

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out (95ms)
</code></pre></div>
<p dir="auto">The issue is only present from <code class="notranslate">v0.37.0</code>.</p>