microsoft/playwright · error · Error
Recording is already in progress.
Error message
Recording is already in progress.
What it means
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.
Source
Thrown at packages/playwright-core/src/tools/backend/context.ts:243
this._video = { params, fileName, fileNames: [] };
const browserContext = await this.ensureBrowserContext();
for (const page of browserContext.pages())
await this._startPageVideo(page);
}
async stopVideoRecording(): Promise<string[]> {
if (!this._video)
return [];
const video = this._video;
for (const page of this._rawBrowserContext.pages())
await page.screencast.stop();
this._video = undefined;
return [...video.fileNames];
}
async startRecording() {
if (this._recordedActions)
throw new Error('Recording is already in progress.');
const browserContext = await this.ensureBrowserContext() as BrowserContextEx;
if (typeof browserContext._enableRecorder !== 'function')
throw new Error('Recording requires a newer version of Playwright, please upgrade.');
const recordedActions: string[] = [];
await browserContext._enableRecorder({
mode: 'recording',
recorderMode: 'api',
omitCallTracking: true,
language: languageGeneratorId(this.codegenLanguage()),
}, {
actionAdded: (page, action, code) => {
recordedActions.push(code);
},
actionUpdated: (page, action, code) => {
if (recordedActions.length)
recordedActions[recordedActions.length - 1] = code;
else
recordedActions.push(code);View on GitHub (pinned to 312030cdce)
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
Example fix
// before
await context.startRecording();
// ... network retry re-sends:
await context.startRecording(); // throws
// after
try { await context.stopRecording(); } catch {}
await context.startRecording(); Defensive patterns
Strategy: validation
Validate before calling
const inProgress = typeof ctx.stopRecording === 'function' && ctx.isRecording?.(); // if exposed if (!inProgress) await ctx.startRecording(); // otherwise just always pair: start → actions → stop, and never re-start
Try / catch
try {
await ctx.startRecording();
} catch (e) {
if ((e as Error).message.includes('already in progress')) { /* session already active; proceed */ }
else throw e;
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- No recording in progress, use ${startRecording.schema.name}
- Recording requires a newer version of Playwright, please upg
- Playwright Extension not found in "${userDataDir}". Install
- Could not start the session "${sessionName}"
- Unknown stream: ${params.streamId}
AI-assisted analysis of microsoft/playwright@312030cdce (2026-08-27).
Data as JSON: /api/errors/204e614d2e0a418c.
Report an issue: GitHub.