{"record":{"id":"4715f56421d0391c","repo":"sipeed/picoclaw","slug":"unexpected-status-s-s","errorCode":null,"errorMessage":"unexpected status %s: %s","messagePattern":"unexpected status (.+?): (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/picoclaw/internal/auth/wecom.go","lineNumber":407,"sourceCode":"\nfunc doWeComJSONGet(ctx context.Context, client *http.Client, targetURL string, out any) error {\n\treq, err := http.NewRequestWithContext(ctx, http.MethodGet, targetURL, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\tbody, readErr := io.ReadAll(io.LimitReader(resp.Body, 8192))\n\t\tif readErr != nil {\n\t\t\treturn fmt.Errorf(\"unexpected status %s\", resp.Status)\n\t\t}\n\t\treturn fmt.Errorf(\"unexpected status %s: %s\", resp.Status, strings.TrimSpace(string(body)))\n\t}\n\n\tif err := json.NewDecoder(resp.Body).Decode(out); err != nil {\n\t\treturn fmt.Errorf(\"decode JSON response: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc wecomPlatformCode() int {\n\tswitch runtime.GOOS {\n\tcase \"darwin\":\n\t\treturn 1\n\tcase \"windows\":\n\t\treturn 2\n\tcase \"linux\":\n\t\treturn 3\n\tdefault:","sourceCodeStart":389,"sourceCodeEnd":425,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/cmd/picoclaw/internal/auth/wecom.go#L389-L425","documentation":"The WeCom HTTP GET returned a non-200 status with a readable body: the error is 'unexpected status <status>: <first 8KB of body>'. This is the primary non-OK diagnostic — e.g. '502 Bad Gateway: <html>...' from a relay behind a load balancer, or a 404 when the endpoint path moved. Because doWeComJSONGet is shared, this surfaces wrapped inside errors 124 and 131.","triggerScenarios":"Relay or its CDN returning 502/503/504; 404 after an endpoint path change between picoclaw and relay versions; 429 from rate limiting; a proxy returning an HTML block page.","commonSituations":"Relay outage or rolling deploy during login; old picoclaw against a moved endpoint; corporate proxy blocking the relay with a 403 page.","solutions":["Read the embedded status and body: 5xx = relay trouble, retry later; 403/404 = endpoint/proxy issue, update picoclaw or fix proxy","curl -v the same URL to confirm it is reproducible outside picoclaw","Retry after a short backoff for 502/503/504","Update picoclaw to the latest release so endpoint paths match the relay"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":"func isRetryableStatus(err error) bool {\n\tmsg := err.Error()\n\treturn strings.Contains(msg, \"unexpected status 502\") ||\n\t\tstrings.Contains(msg, \"unexpected status 503\") ||\n\t\tstrings.Contains(msg, \"unexpected status 504\") ||\n\t\tstrings.Contains(msg, \"unexpected status 429\")\n}","tryCatchPattern":"err := doWeComJSONGet(ctx, client, target, out)\nif isRetryableStatus(err) {\n\ttime.Sleep(backoff)\n\terr = doWeComJSONGet(ctx, client, target, out)\n}\nif err != nil {\n\treturn err\n}","preventionTips":["Retry 5xx/429 with exponential backoff; never retry 4xx except 429","Keep picoclaw updated so endpoint paths match the relay"],"tags":["go","wecom","http","status-code"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}