{"record":{"id":"7fa8b58a46524500","repo":"router-for-me/CLIProxyAPI","slug":"failed-to-parse-refresh-response-w","errorCode":null,"errorMessage":"failed to parse refresh response: %w","messagePattern":"failed to parse refresh response: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/auth/codex/openai_auth.go","lineNumber":257,"sourceCode":"\tbody, errRead := io.ReadAll(resp.Body)\n\tif errRead != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read refresh response: %w\", errRead)\n\t}\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"token refresh failed with status %d: %s\", resp.StatusCode, string(body))\n\t}\n\n\tvar tokenResp struct {\n\t\tAccessToken  string `json:\"access_token\"`\n\t\tRefreshToken string `json:\"refresh_token\"`\n\t\tIDToken      string `json:\"id_token\"`\n\t\tTokenType    string `json:\"token_type\"`\n\t\tExpiresIn    int    `json:\"expires_in\"`\n\t}\n\n\tif errUnmarshal := json.Unmarshal(body, &tokenResp); errUnmarshal != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse refresh response: %w\", errUnmarshal)\n\t}\n\n\t// Extract account ID from ID token\n\tclaims, errParseJWT := ParseJWTToken(tokenResp.IDToken)\n\tif errParseJWT != nil {\n\t\tlog.Warnf(\"Failed to parse refreshed ID token: %v\", errParseJWT)\n\t}\n\n\taccountID := \"\"\n\temail := \"\"\n\tif claims != nil {\n\t\taccountID = claims.GetAccountID()\n\t\temail = claims.Email\n\t}\n\n\treturn &CodexTokenData{\n\t\tIDToken:      tokenResp.IDToken,\n\t\tAccessToken:  tokenResp.AccessToken,","sourceCodeStart":239,"sourceCodeEnd":275,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/auth/codex/openai_auth.go#L239-L275","documentation":"The refresh endpoint returned 200 but the body failed json.Unmarshal into the expected token struct — syntactically invalid JSON, typically rewritten or truncated by an intermediary. Note that claims parsing of the ID token (ParseJWTToken) is deliberately non-fatal (logged as warning), so this error is purely about the outer response not being parseable JSON.","triggerScenarios":"Proxy/portal replacing the refresh response with HTML while keeping 200; truncated body from a buffering middlebox; provider incident serving a malformed payload.","commonSituations":"Background refresh through corporate MITM infrastructure; captive portals on servers that roamed networks; rare upstream content glitches.","solutions":["Log the raw body at debug level to see what was actually served.","Remove the intermediary for the auth domain (proxy bypass rule).","Retry after confirming clean network path; persistent malformed 200s point at the middlebox, not the provider.","Re-login if the stored token has meanwhile expired past recovery."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"td, err := auth.RefreshTokens(ctx, rt)\nif err != nil && strings.Contains(err.Error(), \"failed to parse refresh response\") {\n    // 200 + non-JSON on refresh: suspect middleware rewriting responses\n    log.Errorf(\"non-JSON refresh response: %v\", err)\n}","preventionTips":["Exclude auth domains from MITM proxies.","Log raw bodies at debug level when integrating in restricted networks."],"tags":["oauth","codex","json","proxy","token-refresh"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}