chenhg5/cc-connect · error
qq: ws write: %w
Error message
qq: ws write: %w
What it means
Returned by callAPI when writing the API request frame to the OneBot WebSocket connection fails (p.conn.WriteMessage under p.mu). callAPI is the shared request path for Start, Send, SendImage, and resolveGroupName, so any of these surface this error when the connection is dead. Typically indicates a closed or broken connection.
Source
Thrown at platform/qq/qq.go:561
}
if params != nil {
req["params"] = params
}
ch := make(chan json.RawMessage, 1)
p.echoCh.Store(echo, ch)
defer p.echoCh.Delete(echo)
data, err := json.Marshal(req)
if err != nil {
return nil, err
}
p.mu.Lock()
err = p.conn.WriteMessage(websocket.TextMessage, data)
p.mu.Unlock()
if err != nil {
return nil, fmt.Errorf("qq: ws write: %w", err)
}
select {
case raw := <-ch:
var resp struct {
Status string `json:"status"`
RetCode int `json:"retcode"`
Data json.RawMessage `json:"data"`
}
if json.Unmarshal(raw, &resp) != nil {
return nil, fmt.Errorf("qq: invalid API response")
}
if resp.RetCode != 0 {
return nil, fmt.Errorf("qq: API %s failed (retcode=%d)", action, resp.RetCode)
}
var result map[string]any
_ = json.Unmarshal(resp.Data, &result)
return result, nilView on GitHub (pinned to 4000b2338a)
Solutions
- Reconnect: restart the platform (Start) or implement automatic WS reconnect with backoff.
- Check the wrapped error — 'broken pipe'/'use of closed network connection' confirms a dead socket.
- Enable/verify OneBot heartbeat (ping/pong) so dead connections are detected early.
- Ensure Start completed successfully before issuing API calls; a failed Start leaves conn nil.
- Serialize sends through a healthy-connection check; recreate the socket on first write failure.
Example fix
// before
err = p.conn.WriteMessage(websocket.TextMessage, data)
// after
if p.conn == nil {
return nil, fmt.Errorf("qq: not connected")
}
p.conn.SetWriteDeadline(time.Now().Add(10 * time.Second))
err = p.conn.WriteMessage(websocket.TextMessage, data) Defensive patterns
Strategy: retry
Validate before calling
func (p *Platform) wsHealthy() bool {
p.mu.Lock()
defer p.mu.Unlock()
if p.conn == nil {
return false
}
return p.conn.WriteControl(websocket.PingMessage, nil, time.Now().Add(3*time.Second)) == nil
} Try / catch
result, err := p.callAPI("send_group_msg", params)
if err != nil && strings.Contains(err.Error(), "ws write") {
if rerr := p.reconnect(ctx); rerr != nil {
return fmt.Errorf("qq: reconnect after ws write failure: %w", rerr)
}
result, err = p.callAPI("send_group_msg", params)
} Prevention
- Implement WS auto-reconnect with exponential backoff
- Enable ping/pong keepalive to detect dead sockets early
- Set write deadlines on every frame
- Check Start succeeded before issuing API calls
- Monitor network stability in deployment (sleep, VPN, NAT timeouts)
When it happens
Trigger: Any callAPI invocation while the WebSocket is closed/dropped: server restarted, network blip, ping/pong keepalive missed, or connection never established; concurrent sends racing a reconnect can also hit a nil/stale conn.
Common situations: OneBot server restarted or reconnected while the adapter kept the old socket; laptop sleep/network switch; long-lived idle connection silently dropped by a NAT/firewall without the adapter noticing.
Related errors
- qq: ws connect failed (%s): %w
- wecom-ws: ack timeout
- read register_ack: %w
- cloud_web: websocket disconnected
- qq: send image: %w
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/eaf2fbfedb361eb1.
Report an issue: GitHub.