{"record":{"id":"ffa7c517df05dee8","repo":"microsoft/playwright","slug":"file-must-have-webm-extension","errorCode":null,"errorMessage":"File must have .webm extension","messagePattern":"File must have \\.webm extension","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/playwright-core/src/server/videoRecorder.ts","lineNumber":113,"sourceCode":"  const artifact = recorder.start({ size: recordVideo.size, fileName: path.join(dir, page.guid + '.webm') });\n  page.video = artifact;\n}\n\nclass FfmpegVideoRecorder {\n  private _size: types.Size;\n  private _process: ChildProcess | null = null;\n  private _gracefullyClose: (() => Promise<void>) | null = null;\n  private _firstFrameTimestamp: number = 0;\n  private _lastFrame: { timestamp: number, frameNumber: number, buffer: Buffer } | null = null;\n  private _lastWriteNodeTime: number = 0;\n  private _isStopped = false;\n  private _ffmpegPath: string;\n  private _launchPromise: Promise<Error | null>;\n  private _outputFile: string;\n\n  constructor(ffmpegPath: string, size: types.Size, outputFile: string, page: PageDelegate) {\n    if (!outputFile.endsWith('.webm'))\n      throw new Error('File must have .webm extension');\n    this._outputFile = outputFile;\n    this._ffmpegPath = ffmpegPath;\n    this._size = size;\n    this._launchPromise = this._launch(page).catch(e => e);\n  }\n\n  private async _launch(page: PageDelegate) {\n    await mkdirIfNeeded(this._outputFile);\n    // How to tune the codec:\n    // 1. Read vp8 documentation to figure out the options.\n    //   https://www.webmproject.org/docs/encoder-parameters/\n    // 2. Use the following command to map the options to ffmpeg arguments.\n    //   $ ./third_party/ffmpeg/ffmpeg-mac -h encoder=vp8\n    // 3. A bit more about passing vp8 options to ffmpeg.\n    //   https://trac.ffmpeg.org/wiki/Encode/VP8\n    // 4. Tuning for VP9:\n    //   https://developers.google.com/media/vp9/live-encoding\n    //","sourceCodeStart":95,"sourceCodeEnd":131,"githubUrl":"https://github.com/microsoft/playwright/blob/c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6/packages/playwright-core/src/server/videoRecorder.ts#L95-L131","documentation":"The FfmpegVideoRecorder constructor requires the output file to end in '.webm' because the recorder launches ffmpeg with the VP8/VP9 webm muxer. A different extension would produce a file that mismatches the codec container and later playback/upload would fail. This is a hard precondition checked before spawning ffmpeg.","triggerScenarios":"Constructing FfmpegVideoRecorder with an outputFile whose extension is not '.webm'. In normal Playwright use this is enforced internally (recordVideo path + page.guid + '.webm'), so end users only hit it via custom recorder instantiation or by overriding the video path internals.","commonSituations":"Custom tooling that subclasses or reuses VideoRecorder; monkey-patching the artifacts filename; passing an .mp4/.mov path expecting format conversion (not supported — Playwright only records webm).","solutions":["Always use a '.webm' output path for video recording.","If you need mp4, post-process the .webm with ffmpeg afterwards rather than changing the extension here.","If using recordVideo in context options, leave the filename to Playwright (it appends .webm)."],"exampleFix":"// before\nnew FfmpegVideoRecorder(ffmpeg, size, '/out/video.mp4', page);\n\n// after\nnew FfmpegVideoRecorder(ffmpeg, size, '/out/video.webm', page);","handlingStrategy":"validation","validationCode":"function assertWebm(p) {\n  if (!String(p).endsWith('.webm')) throw new Error('Video output must be .webm');\n}\nassertWebm(outputFile);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always name video files *.webm — Playwright records VP8/VP9 in a webm container only.","Let Playwright pick the filename via recordVideo.dir; it appends .webm.","Convert to mp4 later with ffmpeg, not by changing the extension here."],"tags":["video","ffmpeg","validation","internal"],"backgroundTag":null,"analyzedSha":"c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6","analyzedAt":"2026-08-12T07:26:36.950Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}