mochajs/mocha · error · MochaInstanceAlreadyRunningError

ERR_MOCHA_INSTANCE_ALREADY_RUNNING

ERR_MOCHA_INSTANCE_ALREADY_RUNNING

Error message

Cannot dispose while the mocha instance is still running tests.

What it means

dispose() permanently marks a Mocha instance as disposed and clears references to test/hook functions so the GC can reclaim closures. Calling it while a run is in progress would tear down state the active runner still needs, so Mocha throws when _state is RUNNING.

Source

Thrown at lib/mocha.cjs:622

 * @public
 * @see {@link Mocha#dispose}
 * @param {boolean} cleanReferencesAfterRun
 * @return {Mocha} this
 * @chainable
 */
Mocha.prototype.cleanReferencesAfterRun = function (cleanReferencesAfterRun) {
  this._cleanReferencesAfterRun = cleanReferencesAfterRun !== false;
  return this;
};

/**
 * Manually dispose this mocha instance. Mark this instance as `disposed` and unable to run more tests.
 * It also removes function references to tests functions and hooks, so variables trapped in closures can be cleaned by the garbage collector.
 * @public
 */
Mocha.prototype.dispose = function () {
  if (this._state === mochaStates.RUNNING) {
    throw createMochaInstanceAlreadyRunningError(
      "Cannot dispose while the mocha instance is still running tests.",
    );
  }
  this.unloadFiles();
  this._previousRunner && this._previousRunner.dispose();
  this.suite.dispose();
  this._state = mochaStates.DISPOSED;
};

/**
 * Displays full stack trace upon test failure.
 *
 * @public
 * @see [CLI option](../#-full-trace)
 * @param {boolean} [fullTrace=true] - Whether to print full stacktrace upon failure.
 * @return {Mocha} this
 * @chainable
 */

View on GitHub (pinned to 6bcbee4fd9)

Solutions

  1. Await the run's completion (the promise/exit from run() or runAsync()) before calling dispose()
  2. Move dispose() into a shutdown/after-run path rather than a hook or in-flight callback
  3. Debounce/queue dispose calls so concurrent shutdown logic cannot dispose mid-run

Example fix

// before
mocha.runAsync(failures => {});
mocha.dispose(); // throws if run still in progress
// after
const runner = await mocha.runAsync(failures => {});
await runner;
mocha.dispose(); // safe after run completes
Defensive patterns

Strategy: try-catch

Validate before calling

// only dispose after run finished
if (mocha._state !== 'running') {
  mocha.dispose();
}

Type guard

function isDisposalSafe(mocha) {
  return mocha._state !== 'running';
}

Try / catch

try {
  mocha.dispose();
} catch (err) {
  if (err.code === 'ERR_MOCHA_INSTANCE_ALREADY_RUNNING') {
    await runPromise; // await completion then retry once
    mocha.dispose();
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: Calling mocha.dispose() while mocha.run() (or runAsync()) is still executing and _state === mochaStates.RUNNING.

Common situations: Async cleanup code (e.g. process exit handlers, test-file teardown, watch-mode shutdown) that disposes without awaiting run completion; disposing from a hook or reporter callback during the run.

Related errors


AI-assisted analysis of mochajs/mocha@6bcbee4fd9 (2026-09-01). Data as JSON: /api/errors/c8f561ff1db82e3e. Report an issue: GitHub.