{"record":{"id":"133c93098ea209fa","repo":"tinyhumansai/openhuman","slug":"meet-video-producer-ws-error","errorCode":null,"errorMessage":"[meet-video-producer] ws error","messagePattern":"\\[meet-video-producer\\] ws error","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/src/features/meet/MascotFrameProducer.tsx","lineNumber":356,"sourceCode":"    let ws: WebSocket;\n    try {\n      ws = new WebSocket(url);\n    } catch (err) {\n      console.warn('[meet-video-producer] ws ctor failed', err);\n      return;\n    }\n    ws.binaryType = 'arraybuffer';\n    wsRef.current = ws;\n    ws.onopen = () => {\n      wsReadyRef.current = true;\n      console.log('[meet-video-producer] ws connected', url);\n    };\n    ws.onclose = () => {\n      wsReadyRef.current = false;\n      console.log('[meet-video-producer] ws closed');\n    };\n    ws.onerror = err => {\n      console.warn('[meet-video-producer] ws error', err);\n    };\n\n    const intervalMs = Math.round(1000 / PRODUCER_FPS);\n    const workerSrc =\n      'let t=null;self.onmessage=(e)=>{const d=e.data||{};' +\n      \"if(d.cmd==='start'){clearInterval(t);t=setInterval(()=>self.postMessage('tick'),d.intervalMs);}\" +\n      \"else if(d.cmd==='stop'){clearInterval(t);}};\";\n    const blob = new Blob([workerSrc], { type: 'application/javascript' });\n    const workerUrl = URL.createObjectURL(blob);\n    const worker = new Worker(workerUrl);\n\n    worker.onmessage = () => {\n      void captureFrame();\n    };\n    worker.postMessage({ cmd: 'start', intervalMs });\n\n    // Subscribe to the speak_pump's speaking-state edge events so the\n    // mascot face toggles in sync with the audio participants hear. Done","sourceCodeStart":338,"sourceCodeEnd":374,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/749120085864ce16e0f273c7b86fac7740b39c5b/app/src/features/meet/MascotFrameProducer.tsx#L338-L374","documentation":"The mascot producer's WebSocket to the local frame consumer errored after successful construction (ws.onerror). This fires on connection-level failures — the local consumer refused/dropped the TCP connection or the handshake failed. wsReadyRef stays false (or resets), so pending frames are silently not delivered until the socket recovers or the session ends; onclose follows and logs 'ws closed'.","triggerScenarios":"Thrown at app/src/features/meet/MascotFrameProducer.tsx:356 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Check whether 'ws connected' ever logged for this session — an error before open means the consumer was never reachable","Confirm the local meet frame consumer process is running and listening on the logged port","Loopback firewall rules or an already-bound port can cause handshake failures — verify with a local connection test","Restart the meet session to re-create the producer and socket"],"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"}