{"record":{"id":"38f0e4133fda2ce1","repo":"mastra-ai/mastra","slug":"writemjpegavifile-invalid-dimensions-opts-width","errorCode":null,"errorMessage":"writeMjpegAviFile: invalid dimensions ${opts.width}x${opts.height}","messagePattern":"writeMjpegAviFile: invalid dimensions (.+?)x(.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/core/src/browser/recording/mjpeg-avi.ts","lineNumber":75,"sourceCode":"function fourcc(s: string): Buffer {\n  if (s.length !== 4) {\n    throw new Error(`fourcc must be 4 ASCII characters, got \"${s}\"`);\n  }\n  return Buffer.from(s, 'ascii');\n}\n\n/**\n * Encode a list of MJPEG frames as an AVI 1.0 file.\n *\n * The file is written incrementally to disk so we don't have to hold the whole\n * AVI in memory — large recordings can be hundreds of MB.\n */\nexport function writeMjpegAviFile(filePath: string, frames: readonly MjpegFrame[], opts: MjpegAviOptions): void {\n  if (frames.length === 0) {\n    throw new Error('writeMjpegAviFile: at least one frame is required');\n  }\n  if (opts.width <= 0 || opts.height <= 0 || !Number.isInteger(opts.width) || !Number.isInteger(opts.height)) {\n    throw new Error(`writeMjpegAviFile: invalid dimensions ${opts.width}x${opts.height}`);\n  }\n  if (opts.width > MAX_I16 || opts.height > MAX_I16) {\n    throw new Error(`writeMjpegAviFile: dimensions exceed AVI header bounds: ${opts.width}x${opts.height}`);\n  }\n  for (let i = 0; i < frames.length; i++) {\n    assertJpegFrame(frames[i]!.bytes, i);\n  }\n\n  mkdirSync(dirname(filePath), { recursive: true });\n\n  // Frame rate: derived from the elapsed time between the first and last\n  // captured frames. AVI's main header stores a single dwMicroSecPerFrame, so\n  // playback is even-paced; that matches MJPEG's typical usage.\n  const elapsedMs =\n    frames.length > 1 ? Math.max(1, frames[frames.length - 1]!.timestampMs - frames[0]!.timestampMs) : 1000;\n  const fps = Math.max(1, Math.min(120, Math.round((frames.length * 1000) / elapsedMs)));\n  const microSecPerFrame = Math.round(1_000_000 / fps);\n","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/core/src/browser/recording/mjpeg-avi.ts#L57-L93","documentation":"writeMjpegAviFile validates that opts.width and opts.height are positive integers before writing the AVI stream header, which stores dimensions in fixed-size binary fields that cannot represent zero, negative, or fractional values.","triggerScenarios":"Passing MjpegAviOptions with width or height that is 0, negative, NaN, or fractional (e.g. 0x0, -1x480, 1920.5x1080).","commonSituations":"Dimensions derived from an uninitialized variable or failed image decode returning 0; computing dimensions by division without rounding; passing viewport size before the page finished loading.","solutions":["Round/sanitize dimensions with Math.round/Math.max(1, ...) before constructing MjpegAviOptions","Ensure dimensions come from a successfully decoded frame (decodeJpeg(frame.bytes).width/height)","Add a pre-call check: Number.isInteger(w) && w > 0 && Number.isInteger(h) && h > 0"],"exampleFix":"// before\nwriteMjpegAviFile(outPath, frames, { width: vw / 2, height: vh / 2, fps });\n// after\nwriteMjpegAviFile(outPath, frames, {\n  width: Math.max(1, Math.round(vw / 2)),\n  height: Math.max(1, Math.round(vh / 2)),\n  fps,\n});","handlingStrategy":"validation","validationCode":"function validDims(w, h) {\n  return Number.isInteger(w) && w > 0 && Number.isInteger(h) && h > 0;\n}\nif (!validDims(opts.width, opts.height)) {\n  throw new Error('width/height must be positive integers');\n}","typeGuard":"function hasValidDimensions(o) {\n  return typeof o?.width === 'number' && Number.isInteger(o.width) && o.width > 0\n    && typeof o?.height === 'number' && Number.isInteger(o.height) && o.height > 0;\n}","tryCatchPattern":"try {\n  writeMjpegAviFile(outPath, frames, opts);\n} catch (e) {\n  if (e.message.includes('invalid dimensions')) {\n    // fix dims from a decoded frame and retry once\n  } else throw e;\n}","preventionTips":["Derive dimensions from decodeJpeg(firstFrame).width/height","Use Math.round after any scaling math","Never pass raw viewport objects without validation"],"tags":["avi","dimensions","input-validation"],"backgroundTag":"invalid-dimensions","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T08:17:16.595Z"}