{"record":{"id":"250f2640bd65d01b","repo":"siyuan-note/siyuan","slug":"websocket-not-yet-connected","errorCode":null,"errorMessage":"WebSocket not yet connected","messagePattern":"WebSocket not yet connected","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"kernel/plugin/api_client.go","lineNumber":432,"sourceCode":"\t\t\t\t\t\tb := arrayBuffer.Bytes()\n\t\t\t\t\t\tmessageData = make([]byte, len(b))\n\t\t\t\t\t\tcopy(messageData, b) // ArrayBuffer.Bytes() points into JS engine memory; copy before async send\n\t\t\t\t\t} else {\n\t\t\t\t\t\topcode = gws.OpcodeText\n\t\t\t\t\t\tmessageData = []byte(data.String())\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tsendRunErr := p.worker.Run(func(rt *goja.Runtime) (_ any, err error) {\n\t\t\t\t\tstate := WebSocketState(readyState.Load())\n\t\t\t\t\tif state == WebSocketReadyStateClosing || state == WebSocketReadyStateClosed {\n\t\t\t\t\t\terr = fmt.Errorf(\"WebSocket is not open (state: %d)\", state)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\n\t\t\t\t\tc := gwsConn.Load()\n\t\t\t\t\tif c == nil {\n\t\t\t\t\t\terr = fmt.Errorf(\"WebSocket not yet connected\")\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\n\t\t\t\t\tupdateBufferedAmount(rt, len(messageData))\n\t\t\t\t\tc.WriteAsync(opcode, messageData, func(writeErr error) {\n\t\t\t\t\t\tp.worker.Run(func(rt *goja.Runtime) (_ any, err error) {\n\t\t\t\t\t\t\tif writeErr == nil {\n\t\t\t\t\t\t\t\tupdateBufferedAmount(rt, -len(messageData))\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\terr = writeErr\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t}, func(rt *goja.Runtime, result any, err error) {\n\t\t\t\t\t\t\tif lo.IsNil(err) {\n\t\t\t\t\t\t\t\tif resolveErr := sendResolve(result); resolveErr != nil {\n\t\t\t\t\t\t\t\t\tlogging.LogErrorf(\"[plugin:%s] siyuan.client.socket.send resolve: %v\", p.Name, resolveErr)\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {","sourceCodeStart":414,"sourceCodeEnd":450,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/plugin/api_client.go#L414-L450","documentation":"Returned by socket.send() when readyState is not closing/closed but gwsConn is nil — the underlying gws connection has not been stored yet. The dial has not completed (or open() was never called), so there is no Conn to write to.","triggerScenarios":"Calling send() before awaiting open(), or immediately after socket() returns while the dial is still in flight.","commonSituations":"Plugin forgets to await open() (or call it at all) and sends right away; or sends in a tight loop right after open() without waiting for onopen.","solutions":["Await ws.open() (or wait for onopen) before calling send().","Queue outbound messages until onopen fires."],"exampleFix":"// before\nconst ws = await siyuan.client.socket('/ws/foo');\nws.send('hi'); // rejects: not yet connected\n// after\nconst ws = await siyuan.client.socket('/ws/foo');\nawait ws.open();\nws.send('hi');","handlingStrategy":"validation","validationCode":"await ws.open(); // ensure dial completed\nif (ws.readyState === 1) await ws.send(data);","typeGuard":null,"tryCatchPattern":"try { await ws.send(data); }\ncatch (e) { if (/not yet connected/.test(String(e))) { await ws.open(); await ws.send(data); } }","preventionTips":["Always await open() before the first send.","Buffer messages until onopen fires."],"tags":["client-socket","websocket","send","timing"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}