mochajs/mocha · error · Error
invalid state transition: ${state} => ${newState}
Error message
invalid state transition: ${state} => ${newState} What it means
The ParallelBufferedRunner exposes a read-only `state` property backed by a setter that validates transitions against a finite state machine (`states[state]` lists allowed next states). This error is thrown when code attempts an illegal transition — for example advancing to a new state from RUN_END, or setting a state that can never follow the current one.
Source
Thrown at lib/nodejs/parallel-buffered-runner.cjs:97
/**
* This `Runner` delegates tests runs to worker threads. Does not execute any
* {@link Runnable}s by itself!
* @public
*/
class ParallelBufferedRunner extends Runner {
constructor(...args) {
super(...args);
let state = IDLE;
Object.defineProperty(this, "_state", {
get() {
return state;
},
set(newState) {
if (states[state].has(newState)) {
state = newState;
} else {
throw new Error(`invalid state transition: ${state} => ${newState}`);
}
},
});
this._workerReporter = DEFAULT_WORKER_REPORTER;
this._linkPartialObjects = false;
this._linkedObjectMap = new Map();
this.once(Runner.constants.EVENT_RUN_END, () => {
this._state = COMPLETE;
});
}
/**
* Returns a mapping function to enqueue a file in the worker pool and return results of its execution.
* @param {BufferedWorkerPool} pool - Worker pool
* @param {RunnerOptions} options - Mocha options
* @returns {FileRunner} Mapping functionView on GitHub (pinned to 6bcbee4fd9)
Solutions
- Don't set `runner.state` directly; drive the lifecycle through public APIs (`run()`, `abort()`) and let Mocha manage transitions.
- Create a fresh ParallelBufferedRunner instead of reusing a runner that already reached a terminal state.
- Check the allowed transitions for the current state before setting (inspect the `states` map in parallel-buffered-runner.cjs).
- If a wrapper sets state, log both `state` and `newState` to identify which transition is illegal and fix the ordering.
Example fix
// before
runner.state = 'RUNNING'; // from 'RUN_END' -> illegal transition
// after
const runner = new ParallelBufferedRunner(); // fresh instance
runner.run(files, { serial: false }); Defensive patterns
Strategy: try-catch
Validate before calling
const ALLOWED = { RUNNABLE_START: ['RUNNABLE_END','RUNNABLE_ABORTED'] };
if (!ALLOWED[runner.state]?.includes(newState)) {
throw new Error(`Illegal transition from ${runner.state} to ${newState}; create a new runner instead`);
} Type guard
const canTransition = (runner, newState) => typeof runner.state === 'string' && runner.state !== 'RUN_END' && newState === 'RUNNING';
Try / catch
try {
runner.state = newState;
} catch (err) {
if (err.message.startsWith('invalid state transition')) {
console.error(`${err.message} — create a fresh ParallelBufferedRunner instead of mutating state.`);
runner = new ParallelBufferedRunner();
} else {
throw err;
}
} Prevention
- Never assign runner.state directly; use run()/abort().
- Don't reuse a runner after its run has ended — instantiate a new one.
- Serialize lifecycle mutations to avoid concurrent state writes.
- When upgrading Mocha, re-check any code that manipulates parallel runner internals.
When it happens
Trigger: Programmatically setting `runner.state` to a value not allowed from the current state (e.g. `state = 'RUNNING'` after 'RUN_END'); a third-party wrapper driving the runner's lifecycle manually; double-invoking run/discard paths so the state machine is advanced twice.
Common situations: Custom orchestration of parallel runners in test infrastructure; reusing a completed runner for another run; race conditions where two async paths set state concurrently; version upgrades where the state machine gained new states and old driver code now makes illegal transitions.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
AI-assisted analysis of mochajs/mocha@6bcbee4fd9 (2026-09-01).
Data as JSON: /api/errors/abc8c65977cec97d.
Report an issue: GitHub.