Skip to content
Latchkey

Mocha "Ensure the done() callback is being called" timeout in CI

Mocha waited the default 2000 ms for an async test to finish and it never did. The hint tells you exactly why: the test neither called done() nor returned the promise Mocha could await.

What this error means

An async test fails with "Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure \"done()\" is called; if returning a Promise, ensure it resolves." It is often flakier in CI on a slower runner.

Mocha output
  1) loads config
       Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is
       called; if returning a Promise, ensure it resolves.
       (/home/runner/work/app/test/config.test.js)

Common causes

done() is never called

The test takes a done parameter but a branch (an error, an early return) skips calling it, so Mocha waits until the timeout.

A returned promise that never resolves

The async function awaits work that hangs in CI, so the promise Mocha is waiting on never settles.

How to fix it

Return a promise or call done on every path

  1. Prefer async/await and return the promise instead of using done.
  2. If you keep done, call it in success and error branches.
  3. Mock slow dependencies so the test does not hang on real I/O.
config.test.js
it('loads config', async () => {
  const cfg = await loadConfig();
  expect(cfg.port).to.equal(3000);
});

Raise the timeout for slow work

For a genuinely slow test, increase its timeout rather than leaving it at 2000 ms.

slow.test.js
it('slow', async function () {
  this.timeout(15000);
  // ...
});

How to prevent it

  • Use async/await and return promises instead of the done callback.
  • Mock external I/O so tests do not depend on real timing.
  • Set per-test timeouts for legitimately slow tests.

Frequently asked questions

What causes ""Ensure the done() callback is being called""?
The test takes a done parameter but a branch (an error, an early return) skips calling it, so Mocha waits until the timeout.
How do I fix "Ensure the done() callback is being called"?
Return a promise or call done on every path

Related guides

References

Latchkey auto-heals failures like this one - detected, fixed, and retried without you. Start free → 30-day trial · No credit card