googleworkspace/cli · error · GwsError

People API request failed: {e}

Error message

People API request failed: {e}

What it means

Transport failure in `fetch_profile_display_name`, which calls the People API (`GET https://people.googleapis.com/v1/people/me?personFields=names`) with the Gmail OAuth token to decorate the From display name. `send_with_retry` exhausted its attempts without an HTTP response. Non-2xx (e.g. missing `profile` scope) is a separate `build_api_error` branch.

Source

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

    }

    Ok(result)
}

/// Fetch the authenticated user's display name from the People API.
/// Requires a token with the `profile` scope.
async fn fetch_profile_display_name(
    client: &reqwest::Client,
    token: &str,
) -> Result<Option<String>, GwsError> {
    let resp = crate::client::send_with_retry(|| {
        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.

View on GitHub (pinned to a3768d0e82)

Solutions

  1. Verify egress: `curl -sS https://people.googleapis.com/` must connect (404/400 is fine, TLS failure is not).
  2. Add people.googleapis.com to the proxy/firewall allowlist alongside gmail.googleapis.com.
  3. Retry after restoring connectivity — profile display name is optional decoration and the command re-runs cleanly.
  4. Check `GOOGLE_WORKSPACE_CLI_LOG=gws=debug` output to distinguish connect vs TLS vs DNS.
Defensive patterns

Strategy: retry

Validate before calling

// The People API is a hidden dependency of gmail compose helpers — preflight both hosts
for host in ["gmail.googleapis.com", "people.googleapis.com"] {
    if std::net::TcpStream::connect((host, 443)).is_err() {
        return Err(anyhow::anyhow!("{host} unreachable — gmail helpers need both"));
    }
}

Try / catch

match fetch_profile_display_name(client, token).await {
    // None (no names) is a valid Ok — only Err(GwsError::Other) transport failures warrant retry
    Err(GwsError::Other(e)) if network_transient(&e) => {
        tokio::time::sleep(Duration::from_secs(2)).await;
        fetch_profile_display_name(client, token).await
    }
    other => other,
}

Prevention

When it happens

Trigger: Composing/sending with `gws gmail` while offline; DNS/proxy failure specifically reachable for gmail.googleapis.com but not people.googleapis.com (split egress rules); TLS interception blocking people.googleapis.com.

Common situations: Firewall allowlists that include Gmail but forget people.googleapis.com — a very common cause since the People call is a hidden dependency of the gmail helpers; flaky mobile networks.

Related errors


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