microsoft/playwright · error · Error
Tracing has been already started
Error message
Tracing has been already started
What it means
Tracing.start() throws when an active trace already exists (this._state is set). Tracing is single-instance per context: you must fully stop an existing trace before starting a new one. This protects against overlapping trace writers that would share the same trace/network files.
Source
Thrown at packages/playwright-core/src/server/trace/recorder/tracing.ts:154
}
private _sdkLanguage() {
return this._context instanceof BrowserContext ? this._context._browser.sdkLanguage() : this._context.attribution.playwright.options.sdkLanguage;
}
async resetForReuse(progress: Progress) {
// Discard previous chunk if any and ignore any errors there.
await this.stopChunk(progress, { mode: 'discard' }).catch(() => {});
await progress.race(this._stop());
if (this._snapshotter)
await progress.race(this._snapshotter.resetForReuse());
}
start(progress: Progress, options: TracerOptions) {
if (this._isStopping)
throw new Error('Cannot start tracing while stopping');
if (this._state)
throw new Error('Tracing has been already started');
// Re-write for testing.
this._contextCreatedEvent.sdkLanguage = this._sdkLanguage();
// TODO: passing the same name for two contexts makes them write into a single file
// and conflict.
const traceName = options.name || createGuid();
const tracesDir = this._createTracesDirIfNeeded();
// Init the state synchronously.
this._state = {
options,
traceName,
tracesDir,
traceFile: path.join(tracesDir, traceName + '.trace'),
networkFile: path.join(tracesDir, traceName + '.network'),
chunkOrdinal: 0,View on GitHub (pinned to c8fc3bf8d3)
Solutions
- Guard with tracing.stop() before start, or check that tracing isn't already started.
- Remove the duplicate start call — let only the test runner's trace config own tracing.
- Use a fresh browser context per trace-owned test so _state cannot carry over.
Example fix
// before
await context.tracing.start({ snapshots: true });
await context.tracing.start({ screenshots: true }); // already started
// after
await context.tracing.start({ snapshots: true, screenshots: true });
// ... or stop first:
await context.tracing.stop();
await context.tracing.start({ screenshots: true }); Defensive patterns
Strategy: validation
Validate before calling
async function startOnce(ctx, opts) {
try {
await ctx.tracing.start(opts);
} catch (e) {
if (!/already been started/i.test(String(e.message))) throw e;
// already started; optionally stop and restart with new options
await ctx.tracing.stop();
await ctx.tracing.start(opts);
}
} Try / catch
try { await context.tracing.start(opts); }
catch (e) {
if (/already been started/i.test(String(e.message))) {
await context.tracing.stop();
await context.tracing.start(opts);
} else throw e;
} Prevention
- Centralise tracing.start in one place (runner config or a single beforeAll).
- Always pair start with a stop in a finally block.
- Use a fresh context per test that needs distinct tracing.
When it happens
Trigger: Calling context.tracing.start(...) twice in a row without context.tracing.stop() between them; calling start when the test runner already enabled tracing for the project.
Common situations: A beforeEach hook enables tracing and the test body also calls tracing.start; two suites sharing a browser context both try to own tracing; forgetting to call tracing.stop() at the end of a previous run.
Related errors
- Cannot start tracing while stopping
- Must start tracing before starting a new chunk
- Cannot start a trace chunk while stopping
- Tracing is already stopping
- Must stop trace file before stopping tracing
AI-assisted analysis of microsoft/playwright@c8fc3bf8d3 (2026-08-12).
Data as JSON: /api/errors/eebcc9dd0394bd3f.
Report an issue: GitHub.