{"record":{"id":"55a7feab186900f7","repo":"chenhg5/cc-connect","slug":"qqbot-api-retry-failed-w","errorCode":null,"errorMessage":"qqbot: api retry failed: %w","messagePattern":"qqbot: api retry failed: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/qqbot/qqbot.go","lineNumber":352,"sourceCode":"\t\tif err := p.refreshToken(); err != nil {\n\t\t\treturn fmt.Errorf(\"qqbot: token refresh on 401: %w\", err)\n\t\t}\n\t\ttoken, _ = p.getAccessToken()\n\n\t\tif body != nil {\n\t\t\tdata, _ := json.Marshal(body)\n\t\t\tbodyReader = bytes.NewReader(data)\n\t\t}\n\t\treq2, err := http.NewRequest(method, url, bodyReader)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"qqbot: build retry request: %w\", err)\n\t\t}\n\t\treq2.Header.Set(\"Authorization\", \"QQBot \"+token)\n\t\treq2.Header.Set(\"Content-Type\", \"application/json\")\n\n\t\tresp2, err := core.HTTPClient.Do(req2)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"qqbot: api retry failed: %w\", err)\n\t\t}\n\t\tdefer resp2.Body.Close()\n\n\t\tif resp2.StatusCode >= 300 {\n\t\t\traw, _ := io.ReadAll(resp2.Body)\n\t\t\treturn fmt.Errorf(\"qqbot: api %s %s returned %d (after retry): %s\", method, url, resp2.StatusCode, raw)\n\t\t}\n\t\tif result != nil {\n\t\t\tif err := json.NewDecoder(resp2.Body).Decode(result); err != nil {\n\t\t\t\treturn fmt.Errorf(\"qqbot: decode response: %w\", err)\n\t\t\t}\n\t\t}\n\t\treturn nil\n\t}\n\n\tif resp.StatusCode >= 300 {\n\t\traw, _ := io.ReadAll(resp.Body)\n\t\treturn fmt.Errorf(\"qqbot: api %s %s returned %d: %s\", method, url, resp.StatusCode, raw)","sourceCodeStart":334,"sourceCodeEnd":370,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/qqbot/qqbot.go#L334-L370","documentation":"On the 401-retry path, if the retried HTTP request fails at the transport level (core.HTTPClient.Do returns an error), this wrapped error is returned. Same causes as the initial request failure (DNS, connection, timeout), just occurring on the second attempt after a token refresh.","triggerScenarios":"A 401 was received, refreshToken() succeeded, and the rebuilt request to the QQ API failed at transport level — connection drop, timeout, or TLS error on attempt two.","commonSituations":"Flaky network between host and QQ API where the first failure was auth-related and the second is connectivity; QQ API intermittent outage; long upload bodies timing out on the retry.","solutions":["Treat like the initial transport failure: check connectivity to the QQ API host (curl).","Inspect the wrapped error for timeout vs connection-refused specifics.","Retry the operation after confirming the network is stable.","If uploads are large and timing out, check egress bandwidth/proxy limits.","Ensure no caller context cancels mid-retry."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"if err := net.DialTimeout(\"tcp\", \"api.sgroup.qq.com:443\", 5*time.Second); err != nil {\n    return fmt.Errorf(\"network down; qqbot sends will fail: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"var netErr net.Error\nif errors.As(err, &netErr) && netErr.Timeout() {\n    time.Sleep(2 * time.Second)\n    return retry() // limited retries with backoff\n}","preventionTips":["Retry with exponential backoff on transport errors.","Set sane HTTP client timeouts so retries are prompt.","Avoid cancelling the request context mid-retry.","Monitor packet loss/latency to the QQ API region."],"tags":["qqbot","network","http","retry"],"backgroundTag":"network-request-failed","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"}