{"record":{"id":"6180a3d39cd8942a","repo":"xai-org/grok-build","slug":"failed-to-parse-upload-response","errorCode":null,"errorMessage":"Failed to parse upload response: {}","messagePattern":"Failed to parse upload response: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codegen/xai-file-utils/src/storage_client.rs","lineNumber":1209,"sourceCode":"                    ),\n                }\n                .into());\n            }\n\n            let request = self.add_common_headers(\n                self.http_client\n                    .post(&url)\n                    .header(\"Content-Type\", content_type)\n                    .header(\"X-Storage-Path\", path),\n            );\n\n            match request.body(content.clone()).send().await {\n                Ok(response) if response.status().is_success() => {\n                    self.breaker.record(Outcome::Success);\n                    return response\n                        .json()\n                        .await\n                        .map_err(|e| anyhow::anyhow!(\"Failed to parse upload response: {}\", e));\n                }\n                Ok(response) if response.status() == reqwest::StatusCode::UNAUTHORIZED => {\n                    self.fire_401_attribution(\"upload\");\n                    self.breaker.record(Outcome::Failure);\n                    return Err(HttpUploadError {\n                        status_code: 401,\n                        message: format!(\"{}: HTTP 401 Unauthorized\", operation),\n                    }\n                    .into());\n                }\n                Ok(response) if response.status() == reqwest::StatusCode::FORBIDDEN => {\n                    let body = response.text().await.unwrap_or_default();\n                    tracing::warn!(\"storage upload rejected (403): {body}\");\n                    return Err(HttpUploadError {\n                        status_code: 403,\n                        message: format!(\"{operation}: HTTP 403 Forbidden - {body}\"),\n                    }\n                    .into());","sourceCodeStart":1191,"sourceCodeEnd":1227,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-file-utils/src/storage_client.rs#L1191-L1227","documentation":"After a successful (2xx) upload HTTP request, the client parses the response body as JSON; if reqwest's response.json() fails, this error wraps the reqwest parse error. The upload itself reached the server successfully, but the returned body is not the JSON shape the client expects, so the result cannot be constructed.","triggerScenarios":"Server returning 2xx with empty body, HTML error page from a proxy, or a changed/non-JSON payload; gzip/encoding corruption; reqwest without the right features to decode the response content-type.","commonSituations":"API gateway or reverse proxy intercepting and returning HTML; server version mismatch after backend deploy changed the response schema; auth redirect returning a 2xx login page; misconfigured base URL pointing at the wrong service.","solutions":["Log/inspect the raw response body and content-type to see what the server actually returned.","Verify the storage endpoint/base URL points to the correct GCS proxy API version.","Check for proxies/gateways rewriting responses and bypass or reconfigure them.","Pin client and server versions so the upload response schema matches what the client parses."],"exampleFix":"// before\nreturn response.json().await\n    .map_err(|e| anyhow::anyhow!(\"Failed to parse upload response: {}\", e));\n\n// after\nlet body = response.text().await?;\nserde_json::from_str(&body)\n    .map_err(|e| anyhow::anyhow!(\"Failed to parse upload response: {} (body: {:.200})\", e, body))","handlingStrategy":"try-catch","validationCode":"// Probe the endpoint returns JSON before uploading\nlet probe = reqwest::get(format!(\"{base}/health\")).await?;\nlet ct = probe.headers().get(reqwest::header::CONTENT_TYPE);\nif !ct.map(|v| v.to_str().unwrap_or_default().contains(\"json\")).unwrap_or(false) {\n    anyhow::bail!(\"endpoint is not returning JSON; check base URL/proxy\");\n}","typeGuard":null,"tryCatchPattern":"// Catch parse failures and inspect the raw body\nmatch client.upload(content).await {\n    Ok(resp) => use(resp),\n    Err(e) if e.to_string().starts_with(\"Failed to parse upload response\") => {\n        eprintln!(\"server returned non-JSON: {e:#}; check proxy/base URL\");\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Point the client at the correct API base URL and version.","Bypass proxies/CDNs that rewrite API responses.","Pin client and server versions to a compatible response schema.","Return explicit 204/no-body semantics only when the client expects them."],"tags":["rust","http","json-parsing","upload","reqwest"],"backgroundTag":"invalid-json-response","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}