{"record":{"id":"bcfc0e2ba085ae11","repo":"mastra-ai/mastra","slug":"a-browser-recording-is-already-active-call-browse","errorCode":null,"errorMessage":"A browser recording is already active. Call browser_record with action=\"stop\" before starting a new recording.","messagePattern":"A browser recording is already active\\. Call browser_record with action=\"stop\" before starting a new recording\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/core/src/browser/recording/tools.ts","lineNumber":214,"sourceCode":"\n// ---------------------------------------------------------------------------\n// Lifecycle helpers\n// ---------------------------------------------------------------------------\n\nasync function startRecording(\n  browser: MastraBrowser,\n  opts: {\n    maxDurationMs?: number;\n    everyNthFrame?: number;\n    maxWidth?: number;\n    maxHeight?: number;\n    outputPath?: string;\n    threadId?: string;\n    outputDir: string;\n  },\n): Promise<{ id: string; outputPath: string; maxDurationMs: number }> {\n  if (active) {\n    throw new Error(\n      'A browser recording is already active. Call browser_record with action=\"stop\" before starting a new recording.',\n    );\n  }\n\n  const maxDurationMs = Math.min(\n    HARD_CAP_MAX_DURATION_MS,\n    Math.max(1_000, opts.maxDurationMs ?? DEFAULT_MAX_DURATION_MS),\n  );\n  const everyNthFrame = Math.max(1, Math.floor(opts.everyNthFrame ?? DEFAULT_EVERY_NTH_FRAME));\n  const maxWidth = Math.max(160, Math.floor(opts.maxWidth ?? DEFAULT_MAX_WIDTH));\n  const maxHeight = Math.max(120, Math.floor(opts.maxHeight ?? DEFAULT_MAX_HEIGHT));\n\n  const id = generateRecordingId();\n  const outputPath = resolveOutputPath(id, opts.outputDir, opts.outputPath);\n\n  let stream: ScreencastStream;\n  try {\n    // Bind screencast to the same thread/page the agent is interacting with.","sourceCodeStart":196,"sourceCodeEnd":232,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/core/src/browser/recording/tools.ts#L196-L232","documentation":"The recording module tracks a single active RecordingState; startRecording throws if one is already in progress. Recordings are exclusive, so the caller must stop the current one (browser_record action=\"stop\") before starting a new one.","triggerScenarios":"Calling browser_record action=\"start\" twice without an intervening \"stop\"; a previous recording that never stopped (crashed test, forgotten cleanup); parallel test workers sharing the module state.","commonSituations":"Retry wrappers that re-run a start step after a mid-test failure; concurrent tests in the same process; a stop call that threw earlier leaving state.active set (note: autoStopTimer usually clears it).","solutions":["Call browser_record with action=\"stop\" before starting a new recording","Ensure test cleanup (afterEach) always stops an active recording, even on failure","Avoid running recordings concurrently in the same process/worker","Catch this error on start to detect and recover from a leaked active recording"],"exampleFix":"// before\nawait browser_record({ action: 'start' });\nawait browser_record({ action: 'start' }); // throws\n// after\nawait browser_record({ action: 'start' });\nawait browser_record({ action: 'stop' });\nawait browser_record({ action: 'start' });","handlingStrategy":"try-catch","validationCode":"null","typeGuard":null,"tryCatchPattern":"try {\n  await browser_record({ action: 'start' });\n} catch (e) {\n  if (e.message.includes('already active')) {\n    await browser_record({ action: 'stop' });\n    await browser_record({ action: 'start' });\n  } else throw e;\n}","preventionTips":["Always pair start with stop, including in test cleanup (afterEach/finally)","Never start a recording while another may be active in the same process","Avoid sharing recording state across concurrent test workers"],"tags":["recording","concurrency","state","double-start"],"backgroundTag":"operation-already-active","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}