{"record":{"id":"819e1470401329b8","repo":"sipeed/picoclaw","slug":"decode-json-response-w","errorCode":null,"errorMessage":"decode JSON response: %w","messagePattern":"decode JSON response: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/picoclaw/internal/auth/wecom.go","lineNumber":411,"sourceCode":"\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:\n\t\treturn 0\n\t}\n}\n","sourceCodeStart":393,"sourceCodeEnd":429,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/cmd/picoclaw/internal/auth/wecom.go#L393-L429","documentation":"The WeCom endpoint returned HTTP 200 but the body was not valid JSON for the target struct. Typical causes: the server (or an intercepting proxy/captive portal) returned an HTML page with 200, an empty body, a BOM prefix, or a payload whose types mismatch (string where a number is expected). This error propagates wrapped inside 124/131 depending on which call site hit it.","triggerScenarios":"Captive portal/Wi-Fi sign-in page served instead of the API response; transparent proxy rewriting responses; relay returning an empty 200 during degradation; upstream response schema type change (string errcode vs int) breaking Unmarshal.","commonSituations":"Hotel/airport Wi-Fi intercepting HTTPS via DNS tricks; corporate SSL-inspection proxy injecting its own 200 page; relay partial outage; picoclaw's response structs outdated versus relay.","solutions":["curl the endpoint from the same machine/network and inspect what the body actually is","Connect from an unrestricted network or disable the interfering proxy/VPN","Complete any captive-portal login, then retry the WeCom login","Update picoclaw if the relay's JSON schema changed (type mismatches decode as JSON errors)"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Sniff the body before decoding when a proxy is suspected\nprobe, _ := io.ReadAll(io.LimitReader(resp.Body, 1))\nif len(probe) == 1 && probe[0] == '<' {\n\treturn errors.New(\"received HTML instead of JSON — captive portal or proxy interception\")\n}","typeGuard":"func isJSONDecodeErr(err error) bool {\n\tvar syn *json.SyntaxError\n\tvar typeErr *json.UnmarshalTypeError\n\treturn errors.As(err, &syn) || errors.As(err, &typeErr)\n}","tryCatchPattern":"if err := json.NewDecoder(resp.Body).Decode(out); err != nil {\n\tif isJSONDecodeErr(err) {\n\t\t// likely proxy/captive portal: advise network change instead of retrying blindly\n\t}\n\treturn fmt.Errorf(\"decode JSON response: %w\", err)\n}","preventionTips":["Test from an unrestricted network when HTML-instead-of-JSON appears","Complete captive-portal sign-ins before interactive logins","Disable SSL-inspecting proxies for the relay domain"],"tags":["go","wecom","json","proxy","network"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}