{"record":{"id":"204e614d2e0a418c","repo":"microsoft/playwright","slug":"recording-is-already-in-progress","errorCode":null,"errorMessage":"Recording is already in progress.","messagePattern":"Recording is already in progress\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/playwright-core/src/tools/backend/context.ts","lineNumber":243,"sourceCode":"    this._video = { params, fileName, fileNames: [] };\n    const browserContext = await this.ensureBrowserContext();\n    for (const page of browserContext.pages())\n      await this._startPageVideo(page);\n  }\n\n  async stopVideoRecording(): Promise<string[]> {\n    if (!this._video)\n      return [];\n    const video = this._video;\n    for (const page of this._rawBrowserContext.pages())\n      await page.screencast.stop();\n    this._video = undefined;\n    return [...video.fileNames];\n  }\n\n  async startRecording() {\n    if (this._recordedActions)\n      throw new Error('Recording is already in progress.');\n    const browserContext = await this.ensureBrowserContext() as BrowserContextEx;\n    if (typeof browserContext._enableRecorder !== 'function')\n      throw new Error('Recording requires a newer version of Playwright, please upgrade.');\n    const recordedActions: string[] = [];\n    await browserContext._enableRecorder({\n      mode: 'recording',\n      recorderMode: 'api',\n      omitCallTracking: true,\n      language: languageGeneratorId(this.codegenLanguage()),\n    }, {\n      actionAdded: (page, action, code) => {\n        recordedActions.push(code);\n      },\n      actionUpdated: (page, action, code) => {\n        if (recordedActions.length)\n          recordedActions[recordedActions.length - 1] = code;\n        else\n          recordedActions.push(code);","sourceCodeStart":225,"sourceCodeEnd":261,"githubUrl":"https://github.com/microsoft/playwright/blob/312030cdcee20c006343e5f8420fe451b9aa6390/packages/playwright-core/src/tools/backend/context.ts#L225-L261","documentation":"Thrown by startRecording() when a codegen recording session is already active on the tool backend context. The class tracks in-progress recordings via the _recordedActions field; calling startRecording twice without an intervening stopRecording triggers this guard.","triggerScenarios":"Calling startRecording (MCP tool / tool backend API) twice in a row, e.g. a client retry that re-sends the start request after the first succeeded, or two concurrent tool invocations sharing the same browser context.","commonSituations":"MCP client auto-retries a tool call after a network hiccup; a script loops over pages calling startRecording per page without stopping; stale client state where the user believes recording already stopped but stopRecording was never called.","solutions":["Call stopRecording() before starting a new recording session","If a previous session may be dangling, wrap startRecording in logic that stops and discards the old recording first","Avoid retrying startRecording automatically on transient errors, or make retries idempotent by stopping first"],"exampleFix":"// before\nawait context.startRecording();\n// ... network retry re-sends:\nawait context.startRecording(); // throws\n\n// after\ntry { await context.stopRecording(); } catch {}\nawait context.startRecording();","handlingStrategy":"validation","validationCode":"const inProgress = typeof ctx.stopRecording === 'function' && ctx.isRecording?.(); // if exposed\nif (!inProgress) await ctx.startRecording();\n// otherwise just always pair: start → actions → stop, and never re-start","typeGuard":null,"tryCatchPattern":"try {\n  await ctx.startRecording();\n} catch (e) {\n  if ((e as Error).message.includes('already in progress')) { /* session already active; proceed */ }\n  else throw e;\n}","preventionTips":["Always pair startRecording with stopRecording in a try/finally","Make client retries idempotent: stop (ignoring errors) before re-starting","Don't run two concurrent recording sessions against the same context"],"tags":["recording","codegen","mcp","state"],"backgroundTag":"invalid-state-transition","analyzedSha":"312030cdcee20c006343e5f8420fe451b9aa6390","analyzedAt":"2026-08-27T19:20:32.228Z","contentChangedAt":"2026-08-27T19:20:32.228Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}