Relationships
#1123 flaky test: serve OAuth client tests leak unconsumed fetch response bodies (+ connection_test readDir leak)
Opened by keeb · 7/13/2026
Summary
Running the full suite (deno run test) on main fails with 5 resource-leak
sanitizer errors that are unrelated to any product code — they are
test-harness leaks. Four are deterministic and reproduce in isolation; one
is an order-dependent cross-test readDir leak.
Discovered while verifying the fix for #1121 (a similar OTel timer leak in a workflows test).
Failing tests
Deterministic (fail even when the file is run alone):
src/serve/oauth_client_test.ts:129—startDeviceGrant: throws on HTTP errorsrc/serve/oauth_client_test.ts:405—getUserInfo: throws on HTTP errorsrc/serve/oauth_client_test.ts:445—resolveUsername: throws on 404src/serve/oauth_client_test.ts:466—resolveUsername: throws on other HTTP error
All four fail with:
Leaks detected:
- A fetch response body was created during the test, but not consumed during
the test. Consume or close the response body `ReadableStream`, e.g
`await resp.text()` or `await [HOST-1]()`.Order-dependent (observed in the full-suite run, not in isolation):
src/serve/connection_test.ts:1618—typeArg authz: narrow grant + mismatched typeArg is denied
Leaks detected:
- An async operation to read a directory was started before the test, but
completed during the test. Async operations should not complete in a test
if they were not started in that test. This is often caused by not
collecting all items in the async iterable returned from a `Deno.readDir`
call.Root cause
The OAuth client error paths construct a Response (via fetch) and throw on
non-2xx status without consuming or cancelling the response body. Deno's leak
sanitizer flags the dangling ReadableStream. The connection_test failure is
a separate Deno.readDir iterable that isn't fully drained, surfacing as a
cross-test async-op leak.
Impact
deno run test turns red on a clean checkout independent of the change under
test, masking real regressions locally and (potentially) in CI. Same class of
noise as #1121 and the previously-fixed #645.
Steps to reproduce
# Deterministic (4 failures):
deno test --allow-all src/serve/oauth_client_test.ts
# Full-suite (adds the connection_test readDir leak):
deno run testSuggested fix
Test-only. In the OAuth client error-handling paths, consume or cancel the
response body before throwing (e.g. await resp.body?.cancel() or
await resp.text()), or have the test assert against a body-less error. For
connection_test.ts, fully drain the Deno.readDir async iterable (or scope
the sanitizer with a comment) so the op completes within the test that starts
it.
Environment
- Deno test runner, leak sanitizer on (default under
deno run test). - Reproduces on a pristine
maincheckout; found during #1121.
Closed
No activity in this phase yet.
keeb commented 7/13/2026, 10:03:02 PM
Closing as not-reproducing on the supported toolchain.
The reported leak-sanitizer failures only occur on Deno < 2.8. CI pins deno-version: v2.8.x (resolves to 2.8.3), and Deno 2.8 relaxed the sanitizer so an unconsumed fetch response body is no longer flagged as a resource leak.
Verified with the exact failing file:
- deno 2.7.13 (stale local):
deno test --allow-all src/serve/oauth_client_test.ts→ 16 passed / 4 failed (leaks) - deno 2.8.3 (= CI): same command → 20 passed / 0 failed
So deno run test was never red on the supported Deno; the failures were a stale-local-Deno artifact, not a product or CI regression. Fixed locally by upgrading Deno to match CI.
The underlying nit — cancelling the response body before throwing in the oauth_client.ts error paths — is valid defense-in-depth but low value, so leaving it unfixed.
Sign in to post a ripple.