{"record":{"id":"03a2f28765df55f2","repo":"microsoft/playwright","slug":"cannot-start-tracing-while-stopping","errorCode":null,"errorMessage":"Cannot start tracing while stopping","messagePattern":"Cannot start tracing while stopping","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/playwright-core/src/server/trace/recorder/tracing.ts","lineNumber":152,"sourceCode":"      this._contextCreatedEvent.options = context._options;\n    }\n  }\n\n  private _sdkLanguage() {\n    return this._context instanceof BrowserContext ? this._context._browser.sdkLanguage() : this._context.attribution.playwright.options.sdkLanguage;\n  }\n\n  async resetForReuse(progress: Progress) {\n    // Discard previous chunk if any and ignore any errors there.\n    await this.stopChunk(progress, { mode: 'discard' }).catch(() => {});\n    await progress.race(this._stop());\n    if (this._snapshotter)\n      await progress.race(this._snapshotter.resetForReuse());\n  }\n\n  start(progress: Progress, options: TracerOptions) {\n    if (this._isStopping)\n      throw new Error('Cannot start tracing while stopping');\n    if (this._state)\n      throw new Error('Tracing has been already started');\n\n    // Re-write for testing.\n    this._contextCreatedEvent.sdkLanguage = this._sdkLanguage();\n\n    // TODO: passing the same name for two contexts makes them write into a single file\n    // and conflict.\n    const traceName = options.name || createGuid();\n\n    const tracesDir = this._createTracesDirIfNeeded();\n\n    // Init the state synchronously.\n    this._state = {\n      options,\n      traceName,\n      tracesDir,\n      traceFile: path.join(tracesDir, traceName + '.trace'),","sourceCodeStart":134,"sourceCodeEnd":170,"githubUrl":"https://github.com/microsoft/playwright/blob/c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6/packages/playwright-core/src/server/trace/recorder/tracing.ts#L134-L170","documentation":"The Tracing.start() method refuses to run while a previous stopChunk() is still flushing trace data to disk (the _isStopping flag is set). Tracing has an asynchronous teardown window between stopChunk being called and the chunk file being sealed; starting a new trace inside that window would race with file writes. This guard prevents interleaved chunk state.","triggerScenarios":"Calling context.tracing.start(...) immediately after context.tracing.stopChunk(...) resolves, but before the internal _isStopping flag clears (e.g. the discard in resetForReuse or a manual chunk cycle). Also when two callers (e.g. test runner reuse + user code) invoke tracing.start concurrently.","commonSituations":"Re-enabling tracing inside a beforeEach/test that races with the runner's own tracing teardown; calling tracing.start in parallel from multiple test workers sharing a context; chaining start right after stopChunk({mode:'discard'}) without awaiting the full stop.","solutions":["Await the full tracing lifecycle: call tracing.stop() (or await the chunk completion) before calling tracing.start() again.","If reproducing in the test runner, move tracing.start into a serial hook and ensure no parallel worker touches the same context's tracing.","Add a small await on the context's reuse/reset promise so _isStopping has cleared before you start."],"exampleFix":"// before\nawait context.tracing.stopChunk({ path: 't.zip' });\nawait context.tracing.start({ snapshots: true }); // may hit _isStopping\n\n// after\nawait context.tracing.stopChunk({ path: 't.zip' });\nawait context.tracing.stop();\nawait context.tracing.start({ snapshots: true });","handlingStrategy":"validation","validationCode":"// Avoid calling start while a chunk teardown is in flight.\n// Track an in-progress flag yourself if you orchestrate tracing:\nlet stopping = false;\nasync function safeStart(ctx, opts) {\n  if (stopping) throw new Error('teardown in progress');\n  // ensure prior trace is fully stopped\n  await ctx.tracing.stop().catch(() => {});\n  await ctx.tracing.start(opts);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await context.tracing.start(opts);\n} catch (e) {\n  if (/while stopping/.test(String(e.message))) {\n    await context.tracing.stop().catch(() => {});\n    await context.tracing.start(opts);\n  } else throw e;\n}","preventionTips":["Await the full start->chunk->stopChunk->stop cycle before starting again.","Never call tracing.start in parallel from multiple workers on one context.","Let the test runner own tracing when using its trace config."],"tags":["tracing","state-machine","concurrency"],"backgroundTag":null,"analyzedSha":"c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6","analyzedAt":"2026-08-12T07:26:36.950Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}