mastra-ai/mastra · error · Error
writeMjpegAviFile: invalid dimensions ${opts.width}x${opts.h
Error message
writeMjpegAviFile: invalid dimensions ${opts.width}x${opts.height} What it means
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.
Source
Thrown at packages/core/src/browser/recording/mjpeg-avi.ts:75
function fourcc(s: string): Buffer {
if (s.length !== 4) {
throw new Error(`fourcc must be 4 ASCII characters, got "${s}"`);
}
return Buffer.from(s, 'ascii');
}
/**
* Encode a list of MJPEG frames as an AVI 1.0 file.
*
* The file is written incrementally to disk so we don't have to hold the whole
* AVI in memory — large recordings can be hundreds of MB.
*/
export function writeMjpegAviFile(filePath: string, frames: readonly MjpegFrame[], opts: MjpegAviOptions): void {
if (frames.length === 0) {
throw new Error('writeMjpegAviFile: at least one frame is required');
}
if (opts.width <= 0 || opts.height <= 0 || !Number.isInteger(opts.width) || !Number.isInteger(opts.height)) {
throw new Error(`writeMjpegAviFile: invalid dimensions ${opts.width}x${opts.height}`);
}
if (opts.width > MAX_I16 || opts.height > MAX_I16) {
throw new Error(`writeMjpegAviFile: dimensions exceed AVI header bounds: ${opts.width}x${opts.height}`);
}
for (let i = 0; i < frames.length; i++) {
assertJpegFrame(frames[i]!.bytes, i);
}
mkdirSync(dirname(filePath), { recursive: true });
// Frame rate: derived from the elapsed time between the first and last
// captured frames. AVI's main header stores a single dwMicroSecPerFrame, so
// playback is even-paced; that matches MJPEG's typical usage.
const elapsedMs =
frames.length > 1 ? Math.max(1, frames[frames.length - 1]!.timestampMs - frames[0]!.timestampMs) : 1000;
const fps = Math.max(1, Math.min(120, Math.round((frames.length * 1000) / elapsedMs)));
const microSecPerFrame = Math.round(1_000_000 / fps);
View on GitHub (pinned to 75dd419e61)
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
Example fix
// before
writeMjpegAviFile(outPath, frames, { width: vw / 2, height: vh / 2, fps });
// after
writeMjpegAviFile(outPath, frames, {
width: Math.max(1, Math.round(vw / 2)),
height: Math.max(1, Math.round(vh / 2)),
fps,
}); Defensive patterns
Strategy: validation
Validate before calling
function validDims(w, h) {
return Number.isInteger(w) && w > 0 && Number.isInteger(h) && h > 0;
}
if (!validDims(opts.width, opts.height)) {
throw new Error('width/height must be positive integers');
} Type guard
function hasValidDimensions(o) {
return typeof o?.width === 'number' && Number.isInteger(o.width) && o.width > 0
&& typeof o?.height === 'number' && Number.isInteger(o.height) && o.height > 0;
} Try / catch
try {
writeMjpegAviFile(outPath, frames, opts);
} catch (e) {
if (e.message.includes('invalid dimensions')) {
// fix dims from a decoded frame and retry once
} else throw e;
} Prevention
- Derive dimensions from decodeJpeg(firstFrame).width/height
- Use Math.round after any scaling math
- Never pass raw viewport objects without validation
When it happens
Trigger: Passing MjpegAviOptions with width or height that is 0, negative, NaN, or fractional (e.g. 0x0, -1x480, 1920.5x1080).
Common situations: 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.
Related errors
- writeMjpegAviFile: at least one frame is required
- writeMjpegAviFile: dimensions exceed AVI header bounds: ${op
- Frame dimensions changed during recording: expected ${width}
- Unknown content type: ${(content as any).type}
- Missing authorization code
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/38f0e4133fda2ce1.
Report an issue: GitHub.