microsoft/playwright · error · Error

Must start tracing before starting a new chunk

Error message

Must start tracing before starting a new chunk

What it means

Tracing.startChunk() (which backs tracing.start() when used in two-step mode) requires that Tracing.start() has already allocated the trace state. The chunk model is: start() sets up the trace files once, then startChunk()/stopChunk() carve out recorded segments. Calling startChunk with no _state means the outer trace was never opened.

Source

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

    if (options.screencast)
      this._fs.mkdir(path.join(tracesDir, 'screencast'));
    if (options.snapshotScreen)
      this._fs.mkdir(path.join(tracesDir, 'screenshots'));
    if (options.snapshotAria)
      this._fs.mkdir(path.join(tracesDir, 'aria'));
    this._fs.writeFile(this._state.networkFile, '');
    // Tracing is 10x bigger if we include scripts in every trace.
    if (options.snapshotDom)
      this._harTracer.start({ omitScripts: !options.live });
    this._started = true;
  }

  async startChunk(progress: Progress, options: { name?: string, title?: string } = {}): Promise<{ traceName: string }> {
    if (this._state && this._state.recording)
      await this.stopChunk(progress, { mode: 'discard' });

    if (!this._state)
      throw new Error('Must start tracing before starting a new chunk');
    if (this._isStopping)
      throw new Error('Cannot start a trace chunk while stopping');

    this._state.recording = true;
    this._state.callsInProgress.clear();

    // - Browser context network trace is shared across chunks as it contains resources
    // used to serve page snapshots, so make a copy with the new name.
    // - APIRequestContext network traces are chunk-specific, always start from scratch.
    const preserveNetworkResources = this._context instanceof BrowserContext;
    if (options.name && options.name !== this._state.traceName)
      this._changeTraceName(this._state, options.name, preserveNetworkResources);
    else
      this._allocateNewTraceFile(this._state);
    if (!preserveNetworkResources) {
      this._state.crossChunkFiles = new Set();
      this._fs.writeFile(this._state.networkFile, '');
    }

View on GitHub (pinned to c8fc3bf8d3)

Solutions

  1. Call context.tracing.start(...) once before any startChunk/stopChunk cycle.
  2. Re-check the lifecycle: start() -> startChunk() -> ... -> stopChunk() -> stop().
  3. If using trace: 'on'/'retain-on-failure' in the runner, let the runner manage start() and only call startChunk/stopChunk in after hooks.

Example fix

// before
await context.tracing.startChunk({ name: 'login' }); // no _state

// after
await context.tracing.start({ snapshots: true });
await context.tracing.startChunk({ name: 'login' });
Defensive patterns

Strategy: validation

Validate before calling

// Ensure start() precedes startChunk().
let started = false;
async function beginChunk(ctx, opts, chunkOpts) {
  if (!started) { await ctx.tracing.start(opts); started = true; }
  return ctx.tracing.startChunk(chunkOpts);
}

Prevention

When it happens

Trigger: Calling context.tracing.startChunk(...) before context.tracing.start(...); calling startChunk after a tracing.stop() that cleared _state; using the low-level chunk API directly without the preceding start.

Common situations: Custom tracing orchestration that skips the start step; a test harness that calls stop() between tests but forgets to re-start before the next chunk; partial teardown leaving _state undefined.

Related errors


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