microsoft/playwright · error · Error

Must stop trace file before stopping tracing

Error message

Must stop trace file before stopping tracing

What it means

Tracing.stop() throws when a chunk is still recording (this._state.recording is true). The tracing lifecycle requires that you stop the current chunk (stopChunk) before stopping the whole trace; otherwise the open chunk's files and HAR entries would be left inconsistent.

Source

Thrown at packages/playwright-core/src/server/trace/recorder/tracing.ts:336

    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;
    this._tracesTmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'playwright-tracing-'));
    return this._tracesTmpDir;

View on GitHub (pinned to c8fc3bf8d3)

Solutions

  1. Issue context.tracing.stopChunk(...) before context.tracing.stop().
  2. If you only used tracing.start({ ... }) without manual chunks, use the one-shot API tracing.start + tracing.stop with a stopChunk in between, or rely on the runner.
  3. Verify _state.recording is false (chunk closed) before calling stop().

Example fix

// before
await context.tracing.start({ snapshots: true });
await context.tracing.startChunk({ name: 'flow' });
await context.tracing.stop(); // recording still true

// after
await context.tracing.start({ snapshots: true });
await context.tracing.startChunk({ name: 'flow' });
await context.tracing.stopChunk({ path: 'flow.zip' });
await context.tracing.stop();
Defensive patterns

Strategy: validation

Validate before calling

// Always close the current chunk before stopping the trace.
async function finish(ctx, out) {
  await ctx.tracing.stopChunk({ path: out }).catch(() => {});
  await ctx.tracing.stop();
}

Try / catch

try { await context.tracing.stop(); }
catch (e) {
  if (/Must stop trace file/i.test(String(e.message))) {
    await context.tracing.stopChunk({ mode: 'discard' }).catch(() => {});
    await context.tracing.stop();
  } else throw e;
}

Prevention

When it happens

Trigger: Calling context.tracing.stop() while a startChunk is active and no stopChunk has been issued; calling stop() right after start() without ever starting/stopping a chunk.

Common situations: Using tracing.start() (which under two-step usage needs a chunk) and then calling stop() directly; forgetting the stopChunk step; a custom trace loop that skips chunk teardown.

Related errors


AI-assisted analysis of microsoft/playwright@c8fc3bf8d3 (2026-08-12). Data as JSON: /api/errors/59a316da651e1ed5. Report an issue: GitHub.