{"record":{"id":"d583a97cc98a3790","repo":"larksuite/cli","slug":"failed-to-parse-response-w","errorCode":null,"errorMessage":"failed to parse response: %w","messagePattern":"failed to parse response: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/auth/auth.go","lineNumber":161,"sourceCode":"\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tqueryParams := make(larkcore.QueryParams)\n\tqueryParams.Set(\"lang\", \"zh_cn\")\n\n\tapiResp, err := ac.DoSDKRequest(ctx, &larkcore.ApiReq{\n\t\tHttpMethod:  http.MethodGet,\n\t\tApiPath:     larkauth.ApplicationInfoPath(appId),\n\t\tQueryParams: queryParams,\n\t}, core.AsBot)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar resp appInfoResponse\n\tif err := json.Unmarshal(apiResp.RawBody, &resp); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse response: %w\", err)\n\t}\n\tif resp.Code != 0 {\n\t\treturn nil, classifyAppInfoErr(apiResp.RawBody, resp.Code, resp.Msg, f, appId)\n\t}\n\n\tapp := resp.Data.App\n\townerOpenId := app.Owner.OwnerID\n\tif ownerOpenId == \"\" {\n\t\townerOpenId = app.CreatorID\n\t}\n\n\tvar userScopes []string\n\tfor _, s := range app.Scopes {\n\t\tif s.Scope == \"\" || !slices.Contains(s.TokenTypes, \"user\") {\n\t\t\tcontinue\n\t\t}\n\t\tuserScopes = append(userScopes, s.Scope)\n\t}","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/larksuite/cli/blob/7fd6ef3c07182257ce776cdc5a614e122d5bd4b3/cmd/auth/auth.go#L143-L179","documentation":"getAppInfo calls the Lark auth API (ApplicationInfoPath) and decodes the raw HTTP body into appInfoResponse. If json.Unmarshal fails because the body is not valid JSON or does not match the struct, the error is wrapped as \"failed to parse response\". This distinguishes a decode-level problem from a Lark business error (resp.Code != 0), which is classified separately by classifyAppInfoErr.","triggerScenarios":"Any lark-cli auth command that resolves app info (e.g. app-credential/scopes flows calling getAppInfo) when the API returns a response whose RawBody cannot be unmarshaled: an HTML login/error page, a proxy or captive-portal response, a truncated/garbled body, or an unexpected schema shape after SDK version changes.","commonSituations":"Corporate proxy or VPN intercepting open.feishu.cn and returning HTML; pointing the CLI at a wrong base URL or mock endpoint; an SDK/larkcore upgrade that changed the response envelope so the struct no longer matches; network middleware returning gzip/binary content.","solutions":["Inspect the raw body: re-run with verbose/debug logging (larkcore debug env) to see what was actually returned before the unmarshal failure.","Check network path: bypass proxies/VPNs or fix HTTPS_PROXY settings so requests reach open.feishu.cn directly.","Verify the app ID and endpoint: a wrong appId can hit a route returning a non-JSON error page; confirm with a manual curl of the same path.","Upgrade or pin the lark SDK (larkcore/larkauth) and lark-cli to matching versions so the response schema matches the decoder."],"exampleFix":"// before: opaque wrap hides body contents\nreturn nil, fmt.Errorf(\"failed to parse response: %w\", err)\n// after: include a body snippet to diagnose proxies/HTML responses\nsnippet := apiResp.RawBody\nif len(snippet) > 200 {\n\tsnippet = snippet[:200]\n}\nreturn nil, fmt.Errorf(\"failed to parse response: %w (body: %q)\", err, snippet)","handlingStrategy":"try-catch","validationCode":"// Pre-flight: confirm the API path returns JSON before decoding\nresp, err := http.Get(\"https://open.feishu.cn/open-apis/auth/v3/app_info?app_id=\" + appId)\nif err != nil { return err }\nct := resp.Header.Get(\"Content-Type\")\nif !strings.Contains(ct, \"application/json\") {\n\treturn fmt.Errorf(\"expected JSON, got %s (status %d)\", ct, resp.StatusCode)\n}","typeGuard":"func isJSONDecodeErr(err error) bool {\n\tvar syn *json.SyntaxError\n\tvar typ *json.UnmarshalTypeError\n\treturn errors.As(err, &syn) || errors.As(err, &typ)\n}","tryCatchPattern":"info, err := getAppInfo(ctx, f, appId)\nif err != nil {\n\tif isJSONDecodeErr(err) {\n\t\t// non-JSON body: retry via a different network path or surface a proxy hint\n\t\tlog.Printf(\"API returned non-JSON body: %v\", err)\n\t\treturn retryViaDirectConnection(ctx, appId)\n\t}\n\treturn err\n}","preventionTips":["Run auth commands from networks that reach open.feishu.cn without HTML interception (disable captive portals/ssl-inspection for the domain).","Pin lark-cli and the lark SDK versions together so response schemas stay in sync.","Validate appId format before calling to avoid route mismatch error pages.","Check Content-Type/status of API responses before unmarshaling raw bodies."],"tags":["json","http","parsing","auth"],"backgroundTag":"json-unmarshal-failed","analyzedSha":"7fd6ef3c07182257ce776cdc5a614e122d5bd4b3","analyzedAt":"2026-09-04T21:17:44.649Z","contentChangedAt":"2026-09-04T21:17:44.649Z","schemaVersion":2},"datasetVersion":"2026-09-12T02:17:10.037Z"}