{"record":{"id":"0158975a1a2201a4","repo":"chenhg5/cc-connect","slug":"qq-ws-connect-failed-s-w","errorCode":null,"errorMessage":"qq: ws connect failed (%s): %w","messagePattern":"qq: ws connect failed \\((.+?)\\): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"platform/qq/qq.go","lineNumber":81,"sourceCode":"\t\tallowFrom:             allowFrom,\n\t\tshareSessionInChannel: shareSessionInChannel,\n\t\thttpURL:            httpURL,\n\t}, nil\n}\n\nfunc (p *Platform) Name() string { return \"qq\" }\n\nfunc (p *Platform) Start(handler core.MessageHandler) error {\n\tp.handler = handler\n\n\theader := http.Header{}\n\tif p.token != \"\" {\n\t\theader.Set(\"Authorization\", \"Bearer \"+p.token)\n\t}\n\n\tconn, _, err := websocket.DefaultDialer.Dial(p.wsURL, header)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"qq: ws connect failed (%s): %w\", p.wsURL, err)\n\t}\n\tp.conn = conn\n\n\tslog.Info(\"qq: connected to OneBot\", \"url\", p.wsURL)\n\n\tctx, cancel := context.WithCancel(context.Background())\n\tp.cancel = cancel\n\n\t// Start readLoop BEFORE callAPI: callAPI's response is routed by readLoop,\n\t// so calling it first would always time out after 15s and leave selfID=0,\n\t// which disables the self-message filter in handleMessage and lets the bot\n\t// respond to its own messages.\n\tgo p.readLoop(ctx)\n\n\t// Get bot self info\n\tif info, err := p.callAPI(\"get_login_info\", nil); err == nil {\n\t\tif uid, ok := info[\"user_id\"].(float64); ok {\n\t\t\tp.selfID = int64(uid)","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/qq/qq.go#L63-L99","documentation":"Returned by Platform.Start when the WebSocket dial to the OneBot v11 server (p.wsURL) fails. The QQ platform adapter connects via websocket.DefaultDialer.Dial; any dial-layer failure (TCP, TLS, HTTP handshake, auth rejection) is wrapped with the target URL for debugging. It aborts platform startup, so the QQ platform cannot receive or send messages.","triggerScenarios":"Calling Start() when the OneBot server is unreachable at p.wsURL (wrong host/port, server down), the URL scheme is wrong (ws vs wss), the reverse-proxy returns non-101, or the Bearer token header is rejected and the handshake is refused.","commonSituations":"config.toml has the wrong ws_url for the OneBot/NapCat/Lagrange server; the OneBot service is not running or is listening on a different port; running behind a proxy that rejects WebSocket upgrades; expired or incorrect access token; firewall blocking the connection.","solutions":["Verify the OneBot server is running and reachable: curl the HTTP endpoint or open the ws URL in a WS client.","Check the qq section of config.toml: ws_url host, port, and scheme (ws:// vs wss://) must match the OneBot server config.","If the server requires an access token, confirm p.token matches the OneBot access_token exactly (it is sent as 'Authorization: Bearer <token>').","Inspect the wrapped inner error (%w) for the root cause: connection refused means server down; 401/403 means token mismatch; timeout means network/firewall.","If using wss through a reverse proxy, ensure the proxy forwards the Upgrade and Connection headers."],"exampleFix":"// before\nws_url = \"ws://127.0.0.1:6700\"   // server actually on 3001\n\n// after\nws_url = \"ws://127.0.0.1:3001\"\naccess_token = \"my-onebot-token\"  // must match OneBot access_token","handlingStrategy":"retry","validationCode":"u, err := url.Parse(cfg.QQ.WSURL)\nif err != nil || (u.Scheme != \"ws\" && u.Scheme != \"wss\") {\n    return fmt.Errorf(\"invalid qq ws_url: %q\", cfg.QQ.WSURL)\n}\nconn, err := net.DialTimeout(\"tcp\", u.Host, 5*time.Second)\nif err != nil {\n    return fmt.Errorf(\"onebot server unreachable at %s: %w\", u.Host, err)\n}\nconn.Close()","typeGuard":null,"tryCatchPattern":"err := p.Start(ctx)\nif err != nil && strings.Contains(err.Error(), \"ws connect failed\") {\n    slog.Warn(\"qq ws dial failed, retrying with backoff\", \"err\", err)\n    time.Sleep(backoff)\n    return p.Start(ctx)\n}","preventionTips":["Health-check the OneBot endpoint before starting the platform","Pin ws scheme and port in config and validate on load","Keep access_token in sync with the OneBot access_token","Use wss behind proxies that strip WS upgrade headers only if they support forwarding them"],"tags":["websocket","network","connection","onebot","startup"],"backgroundTag":"connection-refused","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}