mastra-ai/mastra · error · Error
fourcc must be 4 ASCII characters, got "${s}"
Error message
fourcc must be 4 ASCII characters, got "${s}" What it means
The MJPEG-AVI encoder validates every FourCC chunk/RIFF tag before encoding. FourCC codes are by definition exactly 4 ASCII bytes; anything else would corrupt the AVI container structure, so the helper fourcc() throws if the string length is not 4. In practice this fires when internal tag constants are edited or when custom tags are passed incorrectly.
Source
Thrown at packages/core/src/browser/recording/mjpeg-avi.ts:59
const FOURCC_MJPG = fourcc('MJPG');
const FOURCC_MOVI = fourcc('movi');
const FOURCC_IDX1 = fourcc('idx1');
const FOURCC_00DC = fourcc('00dc');
const AVIF_HASINDEX = 0x00000010;
const AVIIF_KEYFRAME = 0x00000010;
const AVIH_SIZE = 56;
const STRH_SIZE = 56;
const STRF_SIZE = 40; // BITMAPINFOHEADER, no extra data
const LIST_TYPE_SIZE = 4; // 4 bytes for the LIST type ("hdrl", "movi", etc.)
const CHUNK_HEADER_SIZE = 8; // fourcc (4) + size (4)
const MAX_U32 = 0xffffffff;
const MAX_I16 = 0x7fff;
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) {View on GitHub (pinned to 75dd419e61)
Solutions
- Correct the tag constant to exactly 4 ASCII characters ('RIFF', 'AVI ', 'LIST', 'hdrl', 'avih', 'strl', ...).
- Pad short tags with spaces (AVI convention) rather than shorter strings.
- Add a unit test covering every tag constant passed to fourcc().
- Check string length at construction time with a compile-time const assertion if extending.
Example fix
// before const FOURCC_AVIH = 'AVIHDR'; // 6 chars -> throws // after const FOURCC_AVIH = 'avih'; // exactly 4 ASCII chars
Defensive patterns
Strategy: validation
Validate before calling
function assertFourcc(s: string): asserts s is Fourcc {
if (s.length !== 4) throw new Error(`invalid fourcc: ${JSON.stringify(s)}`);
}
assertFourcc(customTag); Type guard
type Fourcc = string & { __brand: 'fourcc' };
function isFourcc(s: string): s is Fourcc {
return s.length === 4 && /^[\x20-\x7e]{4}$/.test(s);
} Try / catch
try {
const avi = encodeMjpegAvi(frames, { tags: { avih: customAvihTag } });
} catch (err) {
if (err instanceof Error && err.message.startsWith('fourcc must be 4 ASCII characters')) {
console.error('Bad tag constant:', err.message); // fix the constant, do not retry
}
throw err;
} Prevention
- Keep every tag constant next to the encoder and review lengths in code review.
- Pad tags to 4 chars with spaces (AVI convention: 'AVI ').
- Write a unit test asserting Object.values(TAGS).every(t => t.length === 4).
- Use const-asserted literal types so TypeScript catches bad lengths where possible.
When it happens
Trigger: Passing a string whose length != 4 to fourcc() (directly or via a custom tag constant) — e.g. 'AVII', 'RIFFS', an empty string, or a variable holding a truncated/concatenated tag.
Common situations: Extending the encoder with custom chunk types and mistyping the tag; refactoring constants with accidental whitespace or concatenation; localization/encoding mishaps turning a 4-char tag into a multibyte sequence of different JS length.
Related errors
- writeMjpegAviFile: at least one frame is required
- Recording outputPath must be inside ${baseDir}
- No frames captured during recording
- Frame dimensions changed during recording: expected ${width}
- ClaudeSDKAgent resumeData must include sessionId or continue
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/ec3b18c492a12daf.
Report an issue: GitHub.