siyuan-note/siyuan · warning

WebSocket not yet connected

Error message

WebSocket not yet connected

What it means

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.

Source

Thrown at kernel/plugin/api_client.go:432

						b := arrayBuffer.Bytes()
						messageData = make([]byte, len(b))
						copy(messageData, b) // ArrayBuffer.Bytes() points into JS engine memory; copy before async send
					} else {
						opcode = gws.OpcodeText
						messageData = []byte(data.String())
					}
				}

				sendRunErr := p.worker.Run(func(rt *goja.Runtime) (_ any, err error) {
					state := WebSocketState(readyState.Load())
					if state == WebSocketReadyStateClosing || state == WebSocketReadyStateClosed {
						err = fmt.Errorf("WebSocket is not open (state: %d)", state)
						return
					}

					c := gwsConn.Load()
					if c == nil {
						err = fmt.Errorf("WebSocket not yet connected")
						return
					}

					updateBufferedAmount(rt, len(messageData))
					c.WriteAsync(opcode, messageData, func(writeErr error) {
						p.worker.Run(func(rt *goja.Runtime) (_ any, err error) {
							if writeErr == nil {
								updateBufferedAmount(rt, -len(messageData))
							} else {
								err = writeErr
							}
							return
						}, func(rt *goja.Runtime, result any, err error) {
							if lo.IsNil(err) {
								if resolveErr := sendResolve(result); resolveErr != nil {
									logging.LogErrorf("[plugin:%s] siyuan.client.socket.send resolve: %v", p.Name, resolveErr)
								}
							} else {

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Await ws.open() (or wait for onopen) before calling send().
  2. Queue outbound messages until onopen fires.

Example fix

// before
const ws = await siyuan.client.socket('/ws/foo');
ws.send('hi'); // rejects: not yet connected
// after
const ws = await siyuan.client.socket('/ws/foo');
await ws.open();
ws.send('hi');
Defensive patterns

Strategy: validation

Validate before calling

await ws.open(); // ensure dial completed
if (ws.readyState === 1) await ws.send(data);

Try / catch

try { await ws.send(data); }
catch (e) { if (/not yet connected/.test(String(e))) { await ws.open(); await ws.send(data); } }

Prevention

When it happens

Trigger: Calling send() before awaiting open(), or immediately after socket() returns while the dial is still in flight.

Common situations: 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.

Related errors


AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12). Data as JSON: /api/errors/250f2640bd65d01b. Report an issue: GitHub.