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

  1. Retry the reply-all command.
  2. Confirm no proxy rewrites gmail.googleapis.com responses (curl the profile endpoint and inspect).
  3. For test stubs, return `{"emailAddress": "user@example.com"}` with JSON content type.
  4. 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

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

Related errors


AI-assisted analysis of googleworkspace/cli@a3768d0e82 (2026-08-16). Data as JSON: /api/errors/7366e2c78a2131aa. Report an issue: GitHub.