{"record":{"id":"79e12e0e348efe37","repo":"chenhg5/cc-connect","slug":"decode-response-w-79e12e","errorCode":null,"errorMessage":"decode response: %w","messagePattern":"decode response: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/dingtalk/dingtalk.go","lineNumber":713,"sourceCode":"\t\treturn \"\", fmt.Errorf(\"create request: %w\", err)\n\t}\n\n\treq.Header.Set(\"Content-Type\", \"application/json\")\n\treq.Header.Set(\"x-acs-dingtalk-access-token\", token)\n\n\tresp, err := p.httpClient.Do(req)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"do request: %w\", err)\n\t}\n\tdefer func() { _ = resp.Body.Close() }()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn \"\", fmt.Errorf(\"api returned status %d\", resp.StatusCode)\n\t}\n\n\tvar result downloadResponse\n\tif err := json.NewDecoder(resp.Body).Decode(&result); err != nil {\n\t\treturn \"\", fmt.Errorf(\"decode response: %w\", err)\n\t}\n\n\tif result.DownloadUrl == \"\" {\n\t\treturn \"\", fmt.Errorf(\"empty downloadUrl in response\")\n\t}\n\n\treturn result.DownloadUrl, nil\n}\n\nfunc (p *Platform) getAccessToken() (string, error) {\n\tp.tokenMu.Lock()\n\tdefer p.tokenMu.Unlock()\n\n\t// Return cached token if still valid\n\tif p.accessToken != \"\" && time.Now().Before(p.tokenExpiry) {\n\t\treturn p.accessToken, nil\n\t}\n","sourceCodeStart":695,"sourceCodeEnd":731,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/dingtalk/dingtalk.go#L695-L731","documentation":"After getDownloadURL receives a 200 response from the DingTalk media download API, it decodes the JSON body into a downloadResponse struct. This error wraps any JSON decoding failure — malformed body, wrong content type (e.g. HTML error page behind a proxy), or an unexpected field layout.","triggerScenarios":"handleImageMessage / handleFileMessage / downloadAudio hit this when the download API returns HTTP 200 but a body that is not valid JSON or does not match the expected {\"downloadUrl\": ...} shape — commonly an HTML error page from a gateway, truncated response, or a changed API schema.","commonSituations":"Corporate proxy or CDN intercepting and returning an HTML login/captcha page, DingTalk returning an empty 200 body, Go version mismatch irrelevant but schema drift in DingTalk API responses, or TLS interception appliances re-writing responses.","solutions":["Log the raw response body (before decoding) to see what DingTalk actually returned.","If the body is HTML, a proxy/gateway is interfering — bypass or configure the proxy for api.dingtalk.com.","Verify the DingTalk API schema: the field must be downloadUrl (camelCase) in the response.","Retry once on transient decode failures, then surface the error to the user chat.","Ensure resp.Body isn't already consumed by an earlier io.ReadAll in the same request path."],"exampleFix":"// before: silent about body shape\nvar result downloadResponse\nif err := json.NewDecoder(resp.Body).Decode(&result); err != nil {\n    return \"\", fmt.Errorf(\"decode response: %w\", err)\n}\n\n// after: capture raw body for diagnosis\nraw, _ := io.ReadAll(resp.Body)\nvar result downloadResponse\nif err := json.Unmarshal(raw, &result); err != nil {\n    return \"\", fmt.Errorf(\"decode response %q: %w\", string(raw), err)\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"url, err := p.getDownloadURL(ctx, code)\nif err != nil {\n    if strings.Contains(err.Error(), \"decode response\") {\n        logRawBodyForDiagnosis() // or retry once\n    }\n    return err\n}","preventionTips":["Ensure api.dingtalk.com is reachable without proxy interference (NO_PROXY / bypass rules).","Log raw bodies on decode failure for postmortems.","Don't consume resp.Body twice in the call path.","Watch DingTalk API changelogs for response schema changes."],"tags":["json","dingtalk","api","network"],"backgroundTag":"json-unmarshal-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"}