vitest-dev/vitest · error · Error
done() callback is deprecated, use promise instead
Error message
done() callback is deprecated, use promise instead
What it means
The TestContext object is itself callable in Vitest 4, but invoking it throws because the Mocha-style `test.cb(fn)` done-callback pattern was removed. Vitest now expects tests to signal completion via returned promises/async-await instead of a `done` argument. Calling the context as a function is the only path to this error.
Solutions
- Convert the test to async/await: `test('x', async () => { await something() })`.
- If waiting on an event, wrap it in a Promise and `await` that instead of calling done.
- Remove any `done` parameter from test callbacks entirely.
Example fix
// before
test('waits', (done) => {
emitter.once('ready', done)
})
// after
test('waits', async () => {
await once(emitter, 'ready')
}) Defensive patterns
Strategy: validation
Validate before calling
// Static: ensure no test callback declares a `done` parameter. // grep for `test(.*,\s*\(done\)` and remove.
Prevention
- Always use async/await in test bodies; never declare a done parameter.
- When migrating from Mocha, convert callback-style tests first.
- Wrap event-based async in `util.promisify` or a manual Promise.
When it happens
Trigger: Writing `test('x', (done) => { ...; done() })` and then invoking the injected context as the done callback; porting Mocha callback-style tests verbatim; libraries that call the first function argument they receive.
Common situations: Migrating a Mocha codebase that relied on `done` for async control flow; using event-emitter callbacks that call their last argument as completion.
Related errors
- Signature "test(name, fn, )" was deprecated in Vitest 3 and…
- Async schema validation is not supported in asymmetric…
- --cache.dir is deprecated
- Cannot annotate tests outside of the test run. The test
- Cannot call "onTestFailed" inside a test hook.
AI-assisted analysis of vitest-dev/vitest@1fa9837ec2 (2026-08-11).
Data as JSON: /api/errors/f2bf65cbb5d6727e.
Report an issue: GitHub.
Appendix: source
Thrown at packages/vitest/src/runtime/runner/context.ts:163
const abortControllers = new WeakMap<TestContext, AbortController>()
export function abortIfTimeout([context]: [TestContext?, unknown?], error: Error): void {
if (context) {
abortContextSignal(context, error)
}
}
export function abortContextSignal(context: TestContext, error: Error): void {
const abortController = abortControllers.get(context)
abortController?.abort(error)
}
export function createTestContext(
test: Test,
runner: VitestRunner,
): TestContext {
const context = function () {
throw new Error('done() callback is deprecated, use promise instead')
} as unknown as WriteableTestContext
let abortController = abortControllers.get(context)
if (!abortController) {
abortController = new AbortController()
abortControllers.set(context, abortController)
}
context.signal = abortController.signal
context.task = test
context.skip = (condition?: boolean | string, note?: string): never => {
if (condition === false) {
// do nothing
return undefined as never
}
test.result ??= { state: 'skip' }View on GitHub (pinned to 1fa9837ec2)