microsoft/playwright · error · Error
Tracing is already stopping
Error message
Tracing is already stopping
What it means
Tracing.stop() (via _stop()) throws if a stop is already in flight (the _isStopping flag is set from an ongoing stopChunk). Stopping involves flushing the SerializedFS and clearing _state; a second concurrent stop would double-flush and reset state prematurely.
Source
Thrown at packages/playwright-core/src/server/trace/recorder/tracing.ts:334
state.traceName = name;
state.chunkOrdinal = 0; // Reset ordinal for the new name.
this._allocateNewTraceFile(state);
const newNetworkFile = path.join(state.tracesDir, name + '.network');
if (preserveNetworkResources)
this._fs.copyFile(state.networkFile, newNetworkFile);
state.networkFile = newNetworkFile;
}
async stop(progress: Progress) {
await progress.race(this._stop());
}
private async _stop() {
if (!this._state)
return;
if (this._isStopping)
throw new Error(`Tracing is already stopping`);
if (this._state.recording)
throw new Error(`Must stop trace file before stopping tracing`);
this._closeAllGroups();
this._harTracer.stop();
this.flushHarEntries();
await this._fs.syncAndGetError().finally(() => {
this._state = undefined;
});
}
async deleteTmpTracesDir() {
if (this._tracesTmpDir)
await removeFolders([this._tracesTmpDir]);
}
private _createTracesDirIfNeeded() {
if (this._precreatedTracesDir)
return this._precreatedTracesDir;View on GitHub (pinned to c8fc3bf8d3)
Solutions
- Call tracing.stop() exactly once and await it.
- Ensure stopChunk has fully resolved before calling stop().
- De-duplicate stop calls in your teardown (a single finally block owns the stop).
Example fix
// before
await context.tracing.stopChunk({ path: 't.zip' }); // sets _isStopping briefly
await context.tracing.stop(); // may race
// after
await context.tracing.stopChunk({ path: 't.zip' });
// _isStopping clears after the await; safe to stop
await context.tracing.stop(); Defensive patterns
Strategy: validation
Validate before calling
// Call stop exactly once after stopChunk resolves.
let stopped = false;
async function stopOnce(ctx) {
if (stopped) return;
stopped = true;
await ctx.tracing.stop();
} Try / catch
try { await context.tracing.stop(); }
catch (e) {
if (/already stopping/i.test(String(e.message))) return; // idempotent
throw e;
} Prevention
- Own the stop in a single finally block; do not call it from two teardown paths.
- Ensure stopChunk fully resolved before stop().
- Treat stop as idempotent in your orchestration layer.
When it happens
Trigger: Calling context.tracing.stop() while context.tracing.stopChunk() is mid-flight; calling stop() twice in parallel; the runner and user code both calling stop on the same context.
Common situations: An afterEach hook calls tracing.stop() while the runner's own teardown is also stopping; promise chains that fire stop twice on error paths.
Related errors
- Cannot start tracing while stopping
- Cannot start a trace chunk while stopping
- Tracing has been already started
- Must start tracing before starting a new chunk
- Must stop trace file before stopping tracing
AI-assisted analysis of microsoft/playwright@c8fc3bf8d3 (2026-08-12).
Data as JSON: /api/errors/c255c1bc4c9fb386.
Report an issue: GitHub.