{"record":{"id":"a9e5af5fe5fe3f99","repo":"tinyhumansai/openhuman","slug":"meet-video-producer-capture-failed","errorCode":null,"errorMessage":"[meet-video-producer] capture failed","messagePattern":"\\[meet-video-producer\\] capture failed","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/src/features/meet/MascotFrameProducer.tsx","lineNumber":314,"sourceCode":"              canvasWidth: primaryCanvas.width,\n              canvasHeight: primaryCanvas.height,\n              frameWidth: frameW,\n              frameHeight: frameH,\n              jpegBytes: blob.size,\n              isSpeaking: isSpeakingRef.current,\n              // Dual-mascot diagnostics (issue #4277): whether we drew two\n              // cells this tick, and which slot the audio is on.\n              dualEnabled: dualEnabledNow,\n              secondaryMounted: dualEnabledNow ? Boolean(secondaryCanvas) : undefined,\n              activeMascotSlot: activeMascotSlotRef.current,\n              probe,\n            })\n          );\n        }\n        ws.send(buffer);\n      }\n    } catch (err) {\n      console.warn('[meet-video-producer] capture failed', err);\n    } finally {\n      inflightRef.current = false;\n    }\n  }, [session.requestId]);\n\n  useEffect(() => {\n    stoppedRef.current = false;\n\n    const SILENT_WAV =\n      'data:audio/wav;base64,UklGRigAAABXQVZFZm10IBIAAAABAAEAQB8AAEAfAAABAAgAAABmYWN0BAAAAAAAAABkYXRhAAAAAA==';\n    const keepAliveAudio = document.createElement('audio');\n    keepAliveAudio.muted = true;\n    keepAliveAudio.loop = true;\n    keepAliveAudio.autoplay = true;\n    keepAliveAudio.preload = 'auto';\n    keepAliveAudio.src = SILENT_WAV;\n    keepAliveAudio.style.display = 'none';\n    document.body.appendChild(keepAliveAudio);","sourceCodeStart":296,"sourceCodeEnd":332,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/749120085864ce16e0f273c7b86fac7740b39c5b/app/src/features/meet/MascotFrameProducer.tsx#L296-L332","documentation":"Capturing a composed mascot video frame failed in the meet video producer loop: converting the mascot canvas to a JPEG blob (canvas.toBlob / the frame capture step) rejected for one tick. The diagnostic log includes canvas dimensions, frame size and blob bytes to distinguish a capture that produced an empty/oversized blob from one that rejected outright; the frame is dropped and the loop continues on the next tick.","triggerScenarios":"Thrown at app/src/features/meet/MascotFrameProducer.tsx:314 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Compare frameWidth/frameHeight and jpegBytes in the log — zero dimensions or zero bytes indicate an unmounted/blank canvas","If frames drop repeatedly, check GPU/canvas pressure in the webview (the producer composites primary and secondary mascot canvases per tick)","For one-off failures no action is needed — the producer loop retries on its interval","If persistent, restart the meet session to recreate the canvas and WebSocket pipeline"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"749120085864ce16e0f273c7b86fac7740b39c5b","analyzedAt":"2026-08-17T21:21:45.363Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}