Skip to content
Latchkey

Deno top-level await hang or unresolved promise in CI

A top-level await that never settles keeps the Deno module alive; in CI the job hangs until it times out, or deno test fails because async ops were still pending when the test ended.

What this error means

The job hangs with no further output until the CI timeout, or deno test fails with "error: Test case is leaking async ops" / an operation that never completed.

deno
error: Leaking async ops:
  - A fetch to "https://api.example.com" was started before the test but not completed during the test

Common causes

A top-level await on a promise that never resolves

A network call, timer, or connection at module top level never settles, so the runtime keeps waiting.

Async ops left open at end of test

A test started an operation (fetch, timer, listener) it did not await or close, so Deno reports leaking ops.

How to fix it

Await and close every async operation

  1. Ensure top-level awaits target promises that actually resolve.
  2. In tests, await or abort every started operation and close listeners/timers.
  3. Re-run so no ops leak and the job completes.
main_test.ts
Deno.test("closes resources", async () => {
  const c = new AbortController();
  const res = await fetch(url, { signal: c.signal });
  await res.body?.cancel();
});

Add a job timeout as a safety net

Set a step timeout so a genuine hang fails fast instead of consuming the full CI budget.

.github/workflows/ci.yml
- run: deno test -A
  timeout-minutes: 5

How to prevent it

  • Await or abort every async operation, especially in tests.
  • Avoid top-level awaits on promises that may never resolve.
  • Set step timeouts so hangs fail fast.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →