{"record":{"id":"b9ed23f4f3552842","repo":"chenhg5/cc-connect","slug":"expected-op-10-hello-got-op-d","errorCode":null,"errorMessage":"expected op 10 (Hello), got op %d","messagePattern":"expected op 10 \\(Hello\\), got op (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/qqbot/qqbot.go","lineNumber":726,"sourceCode":"}\n\ntype wsPayload struct {\n\tOp int             `json:\"op\"`\n\tD  json.RawMessage `json:\"d,omitempty\"`\n\tS  *int64          `json:\"s,omitempty\"`\n\tT  string          `json:\"t,omitempty\"`\n}\n\nfunc (p *Platform) waitForHello(conn *websocket.Conn) error {\n\t_ = conn.SetReadDeadline(time.Now().Add(15 * time.Second))\n\tdefer func() { _ = conn.SetReadDeadline(time.Time{}) }()\n\n\tvar msg wsPayload\n\tif err := conn.ReadJSON(&msg); err != nil {\n\t\treturn fmt.Errorf(\"waiting for hello: %w\", err)\n\t}\n\tif msg.Op != opHello {\n\t\treturn fmt.Errorf(\"expected op 10 (Hello), got op %d\", msg.Op)\n\t}\n\n\tvar hello struct {\n\t\tHeartbeatInterval int `json:\"heartbeat_interval\"`\n\t}\n\tif err := json.Unmarshal(msg.D, &hello); err != nil {\n\t\tslog.Warn(\"qqbot: failed to parse Hello payload\", \"error\", err)\n\t}\n\tif hello.HeartbeatInterval > 0 {\n\t\tp.heartbeatMs = hello.HeartbeatInterval\n\t} else {\n\t\tp.heartbeatMs = 41250 // sane default\n\t}\n\tp.heartbeatOK.Store(true)\n\n\tslog.Debug(\"qqbot: received Hello\", \"heartbeat_interval\", p.heartbeatMs)\n\treturn nil\n}","sourceCodeStart":708,"sourceCodeEnd":744,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/qqbot/qqbot.go#L708-L744","documentation":"Returned when the first frame received on the WebSocket is not an op 10 (Hello) dispatch, indicating the server deviated from the QQ gateway protocol. Usually the connection is being rejected or a different op (e.g. an error/close op) arrives first.","triggerScenarios":"After dialing, the server sends a frame whose op code is not opHello — e.g. op 9 (invalid session), an error payload, or a reconnect request instead of Hello.","commonSituations":"QQ protocol/API version drift; connecting with an invalid token causing a non-Hello rejection frame; running an outdated bot SDK against a changed gateway.","solutions":["Log msg.Op and msg.D of the unexpected frame to identify what the server sent","Refresh the access token and reconnect — invalid auth often surfaces as a wrong-op frame","Update to the latest QQ gateway protocol expectations (op codes) if QQ changed them","Retry; if op indicates reconnect, honor the resume flow instead of failing"],"exampleFix":"// before\nif msg.Op != opHello {\n    return fmt.Errorf(\"expected op 10 (Hello), got op %d\", msg.Op)\n}\n// after\nif msg.Op != opHello {\n    return fmt.Errorf(\"expected op 10 (Hello), got op %d payload=%s\", msg.Op, msg.D)\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"func isHelloFrame(msg wsPayload) bool { return msg.Op == opHello }","tryCatchPattern":"if err := p.waitForHello(conn); err != nil {\n    if strings.Contains(err.Error(), \"got op\") {\n        slog.Error(\"unexpected hello frame, reconnecting\", \"err\", err)\n        return p.reconnect()\n    }\n    return err\n}","preventionTips":["Track QQ gateway protocol updates","Log the raw frame payload for every unexpected op","Validate tokens before connecting so rejections surface early"],"tags":["websocket","protocol","handshake","qqbot"],"backgroundTag":"unexpected-response-shape","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}