mocha timeout of 2000ms exceeded in afterEach hook
Fixes Mocha 'timeout of 2000ms exceeded' failures in afterEach hooks by finding the slow cleanup and speeding it up or raising the hook timeout. Use when the failure names an afterEach hook and the tests themselves pass. Not for timeouts inside the test body or in beforeEach setup.
TL;DR
Mocha's default 2s timeout applies to hooks too, and an afterEach doing real async cleanup (closing DB connections, shutting down a server, flushing queues) can blow past it. Await the cleanup properly, make it faster, or raise the timeout on that hook.
Error
Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.
at Hook.[anonymous] (afterEach hook)Steps
- Read the stack and confirm the timeout is on the afterEach hook, not on a test. Expected: the failing hook is named in the output.
- Look at what the hook awaits (db close, server shutdown, file cleanup); add timing logs if it is unclear. Expected: you know which call is slow.
- Make sure the hook returns the promise or awaits it; a floating promise makes Mocha wait out the full timeout and then fail. Expected: the hook function is async and every cleanup call is awaited.
- If cleanup is legitimately slow, raise the timeout on that hook with
this.timeout(10000)inside afunction ()hook (not an arrow function). Expected: the hook gets 10 seconds. - Rerun the file. Expected: the hook completes and the suite passes.
When to use
- The error names afterEach and cites 2000ms.
- Tests pass but the run fails during teardown.
- The afterEach hook closes real resources (database, server, browser).
When not to use
- The timeout is inside a test body; fix the test or the code under test.
- beforeEach times out; the setup is slow, which is a different hook.
- The hook throws immediately; that is an error, not a timeout.
Tool compatibility
- Mocha 8 through 11.
- Applies to before and after hooks as well; the
--timeoutCLI flag sets the suite-wide default.
Variant phrasings
Timeout of 2000ms exceeded, with "(afterEach hook)" in the stack
The hook attribution tells you teardown is the problem, not any test.
ensure "done()" is called, when mixing callbacks and promises
You mixed a done callback with a returned promise. Pick one style; returning the promise is the cleaner fix.
Why it happens
Hooks share the test timeout budget. Async teardown against real infrastructure routinely exceeds 2 seconds, and an un-awaited promise makes Mocha sit through the whole timeout before failing instead of waiting on the work.
Edge cases
- Arrow functions have no mocha
this, sothis.timeoutinside one silently does nothing; usefunction. - A hook that never resolves (a hanging close) needs fixing, not a bigger timeout.
--exitdoes not help here; the hook still runs before the process exits.
Provenance
Resolved from the public thread: https://vectle.com/posts/pst_WdaZ98xVvw0LHiEURXVQgg