{"record":{"id":"ef47045081ca7e1a","repo":"remotion-dev/remotion","slug":"the-video-matting-model-returned-result-data-len","errorCode":null,"errorMessage":"The video matting model returned ${result.data.length} bytes, but ${expectedLength} RGBA bytes were expected.","messagePattern":"The video matting model returned (.+?) bytes, but (.+?) RGBA bytes were expected\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/video-matting/src/video-matting-canvas.ts","lineNumber":87,"sourceCode":"}: {\n\tcontext: VideoMattingCanvasContext;\n\tresult: VideoMattingPipelineResult;\n\tsource: VideoMattingCanvas;\n\ttargetWidth: number;\n\ttargetHeight: number;\n}) => {\n\tif (\n\t\t!Number.isInteger(result.width) ||\n\t\tresult.width <= 0 ||\n\t\t!Number.isInteger(result.height) ||\n\t\tresult.height <= 0\n\t) {\n\t\tthrow new Error('The video matting model returned invalid dimensions.');\n\t}\n\n\tconst expectedLength = result.width * result.height * result.channels;\n\tif (result.data.length !== expectedLength) {\n\t\tthrow new Error(\n\t\t\t`The video matting model returned ${result.data.length} bytes, but ${expectedLength} RGBA bytes were expected.`,\n\t\t);\n\t}\n\n\tconst imageData = new ImageData(result.data, result.width, result.height);\n\n\tcontext.clearRect(0, 0, targetWidth, targetHeight);\n\tif (result.width === targetWidth && result.height === targetHeight) {\n\t\tcontext.putImageData(imageData, 0, 0);\n\t} else {\n\t\tconst intermediateCanvas = createVideoMattingCanvas({\n\t\t\twidth: result.width,\n\t\t\theight: result.height,\n\t\t});\n\t\tconst intermediateContext =\n\t\t\tgetVideoMattingCanvasContext(intermediateCanvas);\n\t\tintermediateContext.putImageData(imageData, 0, 0);\n\t\tcontext.drawImage(intermediateCanvas, 0, 0, targetWidth, targetHeight);","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/remotion-dev/remotion/blob/b2f4e34732f3c6c222ea029413e22dc402218cd7/packages/video-matting/src/video-matting-canvas.ts#L69-L105","documentation":"After dimension validation, drawForegroundFrame checks that result.data contains exactly width * height * channels bytes, matching the expected RGBA buffer for ImageData. A mismatch means the model's pixel buffer and its declared geometry disagree, so drawing would read out-of-bounds or produce garbage. The library surfaces both actual and expected byte counts in the message.","triggerScenarios":"result.data.length !== result.width * result.height * result.channels, e.g. the model returned a buffer sized for a different resolution, a half-finished transfer, or a non-RGBA (channels !== 4) buffer without adjusting the declared channels.","commonSituations":"Mixing model output resolutions when the source video changes size mid-stream, copying only part of the output tensor into result.data, or a backend returning an RGB (3-channel) buffer while channels is still 4.","solutions":["Print result.data.length, result.width, result.height and result.channels to see how the buffer mismatches","Ensure the model output tensor is fully copied and converted to RGBA at the same resolution the model reports","Re-run inference when the video resolution changes instead of reusing a stale buffer","If channels !== 4, convert the buffer to RGBA and set channels to 4 before calling","Skip the frame in a try/catch and continue rendering rather than aborting"],"exampleFix":"// before\nconst out = model.infer(frame); // returns RGB buffer\ndrawForegroundFrame({context, result: {data: out, width: w, height: h, channels: 3}});\n// after\nconst rgba = rgbToRgba(out, w, h);\ndrawForegroundFrame({context, result: {data: rgba, width: w, height: h, channels: 4}});","handlingStrategy":"validation","validationCode":"const expected = result.width * result.height * result.channels;\nif (result.data.length !== expected) throw new Error(`Buffer ${result.data.length} != expected ${expected}`);","typeGuard":"const hasValidBuffer = (r: MattingResult): r is MattingResult =>\n  r.data.length === r.width * r.height * r.channels;","tryCatchPattern":"try {\n  drawForegroundFrame({context, result});\n} catch (err) {\n  if (err instanceof Error && err.message.includes('RGBA bytes were expected')) {\n    console.warn(`Skipping frame: buffer length ${result.data.length} mismatch`);\n    return;\n  }\n  throw err;\n}","preventionTips":["Always convert model output to RGBA (channels=4) before passing it in","Copy the full output tensor; never slice the buffer to a smaller view","Re-run inference when the video resolution changes","Verify buffer length immediately after inference, before drawing"],"tags":["video-matting","validation","buffer-size"],"backgroundTag":"shape-mismatch","analyzedSha":"b2f4e34732f3c6c222ea029413e22dc402218cd7","analyzedAt":"2026-09-09T13:27:51.281Z","contentChangedAt":"2026-09-09T13:27:51.281Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}