{"record":{"id":"e69ee66fc3048412","repo":"microsoft/playwright","slug":"must-start-tracing-before-stopping","errorCode":null,"errorMessage":"Must start tracing before stopping","messagePattern":"Must start tracing before stopping","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/playwright-core/src/server/trace/recorder/tracing.ts","lineNumber":460,"sourceCode":"\n      if (params.mode === 'entries')\n        return { entries: result.entries };\n\n      const artifact = new Artifact(this._context, result.zipFileName);\n      artifact.reportFinished();\n      return { artifact };\n    } finally {\n      // Always release the recording state, even when saving the chunk failed.\n      this._isStopping = false;\n      if (this._state)\n        this._state.recording = false;\n    }\n  }\n\n  private _stopChunk(params: TracingTracingStopChunkParams, coverageFile: string | undefined): { entries: NameValue[], zipFileName: string } | undefined {\n    if (!this._state || !this._state.recording) {\n      if (params.mode !== 'discard')\n        throw new Error(`Must start tracing before stopping`);\n      return undefined;\n    }\n\n    this._closeAllGroups();\n\n    this._context.instrumentation.removeListener(this);\n    eventsHelper.removeEventListeners(this._eventListeners);\n    if (this._state.options.screencast)\n      this._stopScreencast();\n    // We don't need websocket frames outside of the recording window. This also\n    // stops updating websocket content blobs, which we want to stay unchanged for zipping.\n    this._harTracer.setOmitWebSocketFrames(true);\n    if (this._state.options.snapshotDom)\n      this._snapshotter?.stop();\n\n    this.flushHarEntries();\n\n    // Network file survives across chunks, make a snapshot before returning the resulting entries.","sourceCodeStart":442,"sourceCodeEnd":478,"githubUrl":"https://github.com/microsoft/playwright/blob/f1d33b5029be8bbc1095fe88e559117fa3a6243b/packages/playwright-core/src/server/trace/recorder/tracing.ts#L442-L478","documentation":"Tracing.stopChunk() throws when there is no active/recording state AND the requested mode is not 'discard'. A non-discard stopChunk (entries/archive export) requires that tracing was actually started and a chunk recorded; calling it on an idle tracer means there is nothing to export.","triggerScenarios":"Calling context.tracing.stopChunk({ path: 'x.zip' }) (default mode 'archive') or mode 'entries' before tracing.start() / startChunk(); calling export after tracing has already stopped and cleared _state.","commonSituations":"A conditional afterEach that always tries to export a trace even when tracing was disabled for that test; orchestrating chunks without first starting; calling stopChunk twice (second has no state).","solutions":["Only call stopChunk with an export path when you know tracing was started and a chunk is open.","Use mode: 'discard' for the teardown path that must be safe when nothing was recorded.","Guard the export call behind a flag you set in startChunk."],"exampleFix":"// before\nafterEach(async () => {\n  await context.tracing.stopChunk({ path: 'trace.zip' }); // throws if never started\n});\n\n// after\nafterEach(async () => {\n  if (tracingStarted) {\n    await context.tracing.stopChunk({ path: 'trace.zip' });\n  } else {\n    await context.tracing.stopChunk({ mode: 'discard' }).catch(() => {});\n  }\n});","handlingStrategy":"validation","validationCode":"let tracingActive = false;\nasync function guardedStop(ctx, out) {\n  if (!tracingActive) {\n    return ctx.tracing.stopChunk({ mode: 'discard' }).catch(() => ({}));\n  }\n  tracingActive = false;\n  return ctx.tracing.stopChunk({ path: out });\n}","typeGuard":null,"tryCatchPattern":"try { await context.tracing.stopChunk({ path: out }); }\ncatch (e) {\n  if (/Must start tracing before stopping/i.test(String(e.message))) return;\n  throw e;\n}","preventionTips":["Only export when you know a chunk was started and is open.","Use mode:'discard' for safe teardown that may run when nothing was recorded.","Set/clear a flag around startChunk/stopChunk in your harness."],"tags":["tracing","state-machine","lifecycle"],"backgroundTag":null,"analyzedSha":"f1d33b5029be8bbc1095fe88e559117fa3a6243b","analyzedAt":"2026-09-21T21:58:31.278Z","contentChangedAt":"2026-09-21T21:58:31.278Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}