googleworkspace/cli · error · GwsError
Failed to parse profile: {e}
Error message
Failed to parse profile: {e} What it means
The Gmail profile endpoint returned 2xx but `resp.json::<Value>()` failed to parse the body. The profile endpoint always returns JSON (`{"emailAddress": ..., "messagesTotal": ...}`), so a non-JSON body indicates an intercepting proxy, captive portal, or truncated response rather than anything scope- or token-related.
Source
Thrown at crates/google-workspace-cli/src/helpers/gmail/reply.rs:202
.map_err(|e| GwsError::Other(anyhow::anyhow!("Failed to fetch user profile: {e}")))?;
if !resp.status().is_success() {
let status = resp.status().as_u16();
let body = resp
.text()
.await
.unwrap_or_else(|_| "(error body unreadable)".to_string());
return Err(super::build_api_error(
status,
&body,
"Failed to fetch user profile",
));
}
let profile: Value = resp
.json()
.await
.map_err(|e| GwsError::Other(anyhow::anyhow!("Failed to parse profile: {e}")))?;
profile
.get("emailAddress")
.and_then(|v| v.as_str())
.map(|s| s.to_string())
.ok_or_else(|| GwsError::Other(anyhow::anyhow!("Profile missing emailAddress")))
}
// --- Message construction ---
fn extract_reply_to_address(original: &OriginalMessage) -> Vec<Mailbox> {
match &original.reply_to {
Some(reply_to) => reply_to.clone(),
None => vec![original.from.clone()],
}
}
fn build_reply_all_recipients(View on GitHub (pinned to a3768d0e82)
Solutions
- Retry the reply-all command.
- Confirm no proxy rewrites gmail.googleapis.com responses (curl the profile endpoint and inspect).
- For test stubs, return `{"emailAddress": "user@example.com"}` with JSON content type.
- Capture body prefix in logs if it persists.
Defensive patterns
Strategy: validation
Validate before calling
let ct = resp.headers().get(reqwest::header::CONTENT_TYPE).and_then(|v| v.to_str().ok()).unwrap_or("");
if !ct.contains("json") { return Err(anyhow::anyhow!("profile response not JSON ({ct})")); } Type guard
fn is_profile_envelope(v: &serde_json::Value) -> bool {
v.get("emailAddress").and_then(|e| e.as_str()).is_some() || v.get("historyId").is_some()
} Try / catch
let text = resp.text().await?;
let profile: Value = serde_json::from_str(&text)
.map_err(|e| anyhow::anyhow!("profile body not JSON ({e}): {}", &text[..text.len().min(120)]))?;
if !is_profile_envelope(&profile) { return Err(anyhow::anyhow!("unexpected profile envelope")); } Prevention
- Content-type check before json() catches interceptor pages masquerading as 200.
- Retry once on parse failure.
- Stub the profile endpoint as `{"emailAddress": "user@example.com"}` in tests.
When it happens
Trigger: Proxy returning 200 with HTML; body truncated mid-transfer on unstable links; stub server misconfigured in tests.
Common situations: reply-all runs on corporate networks with TLS inspection; CI environments routing googleapis traffic through a rewriting gateway.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Failed to parse message: {e}
- Failed to parse sendAs response: {e}
- Failed to parse attachment JSON: {e}
- Failed to parse People API response: {e}
- Failed to parse calendar list: {e}
AI-assisted analysis of googleworkspace/cli@a3768d0e82 (2026-08-16).
Data as JSON: /api/errors/7366e2c78a2131aa.
Report an issue: GitHub.