{"record":{"id":"ec3b18c492a12daf","repo":"mastra-ai/mastra","slug":"fourcc-must-be-4-ascii-characters-got-s","errorCode":null,"errorMessage":"fourcc must be 4 ASCII characters, got \"${s}\"","messagePattern":"fourcc must be 4 ASCII characters, got \"(.+?)\"","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/core/src/browser/recording/mjpeg-avi.ts","lineNumber":59,"sourceCode":"const FOURCC_MJPG = fourcc('MJPG');\nconst FOURCC_MOVI = fourcc('movi');\nconst FOURCC_IDX1 = fourcc('idx1');\nconst FOURCC_00DC = fourcc('00dc');\n\nconst AVIF_HASINDEX = 0x00000010;\nconst AVIIF_KEYFRAME = 0x00000010;\n\nconst AVIH_SIZE = 56;\nconst STRH_SIZE = 56;\nconst STRF_SIZE = 40; // BITMAPINFOHEADER, no extra data\nconst LIST_TYPE_SIZE = 4; // 4 bytes for the LIST type (\"hdrl\", \"movi\", etc.)\nconst CHUNK_HEADER_SIZE = 8; // fourcc (4) + size (4)\nconst MAX_U32 = 0xffffffff;\nconst MAX_I16 = 0x7fff;\n\nfunction 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) {","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/core/src/browser/recording/mjpeg-avi.ts#L41-L77","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nconst FOURCC_AVIH = 'AVIHDR'; // 6 chars -> throws\n// after\nconst FOURCC_AVIH = 'avih'; // exactly 4 ASCII chars","handlingStrategy":"validation","validationCode":"function assertFourcc(s: string): asserts s is Fourcc {\n  if (s.length !== 4) throw new Error(`invalid fourcc: ${JSON.stringify(s)}`);\n}\nassertFourcc(customTag);","typeGuard":"type Fourcc = string & { __brand: 'fourcc' };\nfunction isFourcc(s: string): s is Fourcc {\n  return s.length === 4 && /^[\\x20-\\x7e]{4}$/.test(s);\n}","tryCatchPattern":"try {\n  const avi = encodeMjpegAvi(frames, { tags: { avih: customAvihTag } });\n} catch (err) {\n  if (err instanceof Error && err.message.startsWith('fourcc must be 4 ASCII characters')) {\n    console.error('Bad tag constant:', err.message); // fix the constant, do not retry\n  }\n  throw err;\n}","preventionTips":["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."],"tags":["avi","validation","recording","fourcc"],"backgroundTag":"invalid-fourcc-tag","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}