googleworkspace/cli · error · GwsError

Failed to parse People API response: {e}

Error message

Failed to parse People API response: {e}

What it means

The People API responded 2xx but `resp.json::<Value>()` could not parse the body as JSON. The People API normally returns well-formed JSON, so a malformed body almost always means an intermediary (proxy, captive portal) rewrote the response, or the body was truncated in transit.

Source

Thrown at crates/google-workspace-cli/src/helpers/gmail/mod.rs:667

        client
            .get("https://people.googleapis.com/v1/people/me")
            .query(&[("personFields", "names")])
            .bearer_auth(token)
    })
    .await
    .map_err(|e| GwsError::Other(anyhow::anyhow!("People API request failed: {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(build_api_error(status, &body, "People API request failed"));
    }

    let body: Value = resp.json().await.map_err(|e| {
        GwsError::Other(anyhow::anyhow!("Failed to parse People API response: {e}"))
    })?;

    Ok(parse_profile_display_name(&body))
}

/// Extract the display name from a People API `people.get` response.
fn parse_profile_display_name(body: &Value) -> Option<String> {
    body.get("names")
        .and_then(|v| v.as_array())
        .and_then(|names| names.first())
        .and_then(|n| n.get("displayName"))
        .and_then(|v| v.as_str())
        .filter(|s| !s.is_empty())
        .map(sanitize_control_chars)
}

/// Fetch binary data for a single attachment from the Gmail API.
///

View on GitHub (pinned to a3768d0e82)

Solutions

  1. Retry the gmail helper command.
  2. Confirm no proxy rewrites people.googleapis.com responses.
  3. In tests, stub the endpoint with `{"names": []}` and a JSON content type.
  4. Log the raw body prefix to identify the interceptor (see example fix pattern).
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.starts_with("application/json") {
    return Err(anyhow::anyhow!("People API returned '{ct}' — likely proxy interception"));
}

Type guard

fn is_people_get_response(v: &serde_json::Value) -> bool {
    // resourceName is mandatory on people.get responses; names may be absent
    v.get("resourceName").and_then(|r| r.as_str()).is_some()
}

Try / catch

let text = resp.text().await?;
let body: Value = serde_json::from_str(&text)
    .map_err(|e| anyhow::anyhow!("People API invalid JSON ({e}): {}", &text[..text.len().min(120)]))?;
if !is_people_get_response(&body) { return Err(anyhow::anyhow!("unexpected People API envelope")); }

Prevention

When it happens

Trigger: Intercepting proxy returning an HTML block page with 200; connection cut mid-body so every retry also truncates; stub server in tests returning non-JSON.

Common situations: Same contexts as error 27 — corporate proxies and unstable networks — plus test harnesses that stub people.googleapis.com incorrectly.

Understand the failure class

Related errors


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