{"record":{"id":"f16b297a1d6b3ab0","repo":"sigoden/aichat","slug":"invalid-response-data-value","errorCode":null,"errorMessage":"Invalid response data: {value}","messagePattern":"Invalid response data: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"src/client/vertexai.rs","lineNumber":487,"sourceCode":"    file: &Option<String>,\n) -> Result<(String, i64)> {\n    let credentials = load_adc(file).await?;\n    let value: Value = client\n        .post(\"https://oauth2.googleapis.com/token\")\n        .json(&credentials)\n        .send()\n        .await?\n        .json()\n        .await?;\n\n    if let (Some(access_token), Some(expires_in)) =\n        (value[\"access_token\"].as_str(), value[\"expires_in\"].as_i64())\n    {\n        Ok((access_token.to_string(), expires_in))\n    } else if let Some(err_msg) = value[\"error_description\"].as_str() {\n        bail!(\"{err_msg}\")\n    } else {\n        bail!(\"Invalid response data: {value}\")\n    }\n}\n\nasync fn load_adc(file: &Option<String>) -> Result<Value> {\n    let adc_file = file\n        .as_ref()\n        .map(PathBuf::from)\n        .or_else(default_adc_file)\n        .ok_or_else(|| anyhow!(\"No application_default_credentials.json\"))?;\n    let data = tokio::fs::read_to_string(adc_file).await?;\n    let data: Value = serde_json::from_str(&data)?;\n    if let (Some(client_id), Some(client_secret), Some(refresh_token)) = (\n        data[\"client_id\"].as_str(),\n        data[\"client_secret\"].as_str(),\n        data[\"refresh_token\"].as_str(),\n    ) {\n        Ok(json!({\n            \"client_id\": client_id,","sourceCodeStart":469,"sourceCodeEnd":505,"githubUrl":"https://github.com/sigoden/aichat/blob/82976d349ad97ac9aae0655ad631dace5e2a6385/src/client/vertexai.rs#L469-L505","documentation":"Thrown by fetch_access_token in src/client/vertexai.rs:487 when the OAuth2 token response JSON contains neither a valid access_token/expires_in pair nor an error_description field. The library embeds the entire raw response value in the message because it cannot interpret what the token endpoint returned. It indicates an unexpected response shape from Google's OAuth token endpoint — likely a proxy, wrong URL, or API change.","triggerScenarios":"Calling prepare_gcloud_access_token -> fetch_access_token where the parsed response JSON lacks access_token and expires_in and also lacks error_description — e.g. a corporate proxy returning an HTML login page, a typo'd token endpoint URL, a 500 JSON body with only {\"error\":\"internal_error\"}, or a captive portal response.","commonSituations":"Corporate proxies/firewalls intercepting the token request; misconfigured token_uri in the service account credentials JSON; Google-side transient 5xx with unexpected bodies; VPN/captive-portal environments; credentials JSON from a non-Google or wrong-format file.","solutions":["Inspect the raw `value` JSON in the error message to see what the token endpoint actually returned.","Check network path — disable/inspect corporate proxies or VPNs intercepting https traffic to oauth2.googleapis.com.","Verify the token_uri field in the service account credentials JSON points to https://oauth2.googleapis.com/token.","Retry — transient Google 5xx responses can produce bodies without access_token.","Re-download the service account credentials JSON to ensure it has a valid token_uri and key fields."],"exampleFix":"// before\n// credentials.json with token_uri: \"https://wrong-endpoint.example.com/token\"\n// after\n// credentials.json with token_uri: \"https://oauth2.googleapis.com/token\"","handlingStrategy":"try-catch","validationCode":"// Pre-flight: ensure the credentials JSON has a sane token_uri before requesting a token\nfn validate_token_uri(creds: &serde_json::Value) -> anyhow::Result<()> {\n    let uri = creds[\"token_uri\"].as_str().unwrap_or_default();\n    anyhow::ensure!(uri == \"https://oauth2.googleapis.com/token\", \"unexpected token_uri: {uri}\");\n    Ok(())\n}","typeGuard":null,"tryCatchPattern":"let token = match prepare_gcloud_access_token().await {\n    Ok(t) => t,\n    Err(e) if e.to_string().contains(\"Invalid response data\") => {\n        // likely proxy/HTML interception or transient Google 5xx\n        tokio::time::sleep(Duration::from_secs(2)).await;\n        prepare_gcloud_access_token().await.map_err(|e2| anyhow::anyhow!(\"token exchange returned unexpected body: {e2}\"))?\n    }\n    Err(e) => return Err(e.into()),\n};","preventionTips":["Log the raw response body embedded in the error message to detect HTML/proxy interception.","Bypass corporate proxies for oauth2.googleapis.com (NO_PROXY) or configure trusted egress.","Verify token_uri in the service account credentials JSON points to https://oauth2.googleapis.com/token.","Add one automatic retry with backoff for token exchange calls — Google 5xx bodies lack error_description.","Validate credentials files at startup so malformed/wrong-format JSON fails fast before token calls."],"tags":["oauth","authentication","google-cloud","vertex-ai","unexpected-response"],"backgroundTag":"unexpected-api-response-shape","analyzedSha":"82976d349ad97ac9aae0655ad631dace5e2a6385","analyzedAt":"2026-09-09T18:33:06.139Z","contentChangedAt":"2026-09-09T18:33:06.139Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}