{"record":{"id":"31291899cf4d138d","repo":"chenhg5/cc-connect","slug":"yuanbao-parse-response-w","errorCode":null,"errorMessage":"yuanbao: parse response: %w","messagePattern":"yuanbao: parse response: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/yuanbao/sign.go","lineNumber":175,"sourceCode":"\t\trespBody, _ := io.ReadAll(resp.Body)\n\t\t_ = resp.Body.Close()\n\t\tif resp.StatusCode != http.StatusOK {\n\t\t\tlastErr = fmt.Errorf(\"yuanbao: sign token API returned %d: %s\", resp.StatusCode, string(respBody))\n\t\t\tcontinue\n\t\t}\n\n\t\tvar result struct {\n\t\t\tCode int `json:\"code\"`\n\t\t\tData *struct {\n\t\t\t\tToken    string `json:\"token\"`\n\t\t\t\tBotID    string `json:\"bot_id\"`\n\t\t\t\tDuration int    `json:\"duration\"`\n\t\t\t\tProduct  string `json:\"product\"`\n\t\t\t\tSource   string `json:\"source\"`\n\t\t\t} `json:\"data\"`\n\t\t}\n\t\tif err := json.Unmarshal(respBody, &result); err != nil {\n\t\t\tlastErr = fmt.Errorf(\"yuanbao: parse response: %w\", err)\n\t\t\tcontinue\n\t\t}\n\t\tif result.Code == 10099 && attempt < maxRetries {\n\t\t\tcontinue\n\t\t}\n\t\tif result.Code != 0 {\n\t\t\treturn nil, fmt.Errorf(\"yuanbao: sign token error code=%d\", result.Code)\n\t\t}\n\t\tif result.Data == nil {\n\t\t\treturn nil, fmt.Errorf(\"yuanbao: sign token response missing data\")\n\t\t}\n\t\treturn &tokenData{\n\t\t\ttoken: result.Data.Token, botID: result.Data.BotID,\n\t\t\tduration: result.Data.Duration, product: result.Data.Product,\n\t\t\tsource: result.Data.Source,\n\t\t}, nil\n\t}\n\treturn nil, lastErr","sourceCodeStart":157,"sourceCodeEnd":193,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/yuanbao/sign.go#L157-L193","documentation":"The 200 response body from the yuanbao sign-token API could not be decoded into the expected {code, data:{token,bot_id,duration,product,source}} envelope. json.Unmarshal failed, the error is wrapped and the loop retries; after maxRetries the last error is returned. This signals the endpoint returned JSON in an unexpected shape or non-JSON content.","triggerScenarios":"json.Unmarshal(respBody, &result) fails during a fetchToken attempt — empty body, HTML error page from a proxy, or a changed/re-versioned API response schema.","commonSituations":"A reverse proxy or captive portal returning an HTML login page with 200 status, api_domain pointing at a wrong service that returns different JSON, upstream API schema change after a version bump.","solutions":["Log/print the raw respBody to see what was actually returned (HTML page? different JSON shape?).","Confirm api_domain points at the genuine sign-token endpoint, not a proxy or different service.","Check whether the yuanbao API version changed and update the response struct in platform/yuanbao/sign.go accordingly.","If behind a corporate proxy, bypass it for this host so the real API response is received."],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":"if !json.Valid(respBody) { return fmt.Errorf(\"non-JSON response: %.200s\", respBody) }","typeGuard":"func looksLikeTokenEnvelope(b []byte) bool {\n    var probe struct{ Code *int `json:\"code\"` }\n    return json.Unmarshal(b, &probe) == nil && probe.Code != nil\n}","tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"parse response\") {\n    slog.Error(\"unexpected sign-token body\", \"body\", string(respBody))\n}","preventionTips":["Log raw response bodies on decode failure for diagnosis","Pin/verify the upstream API version in integration tests","Bypass proxies that could rewrite the response"],"tags":["json","api","unmarshal","response-shape"],"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-14T05:17:10.506Z"}