{"record":{"id":"816ada909c10e317","repo":"googleworkspace/cli","slug":"people-api-request-failed-e","errorCode":null,"errorMessage":"People API request failed: {e}","messagePattern":"People API request failed: (.+?)","errorType":"exception","errorClass":"GwsError","httpStatus":null,"severity":"error","filePath":"crates/google-workspace-cli/src/helpers/gmail/mod.rs","lineNumber":655,"sourceCode":"    }\n\n    Ok(result)\n}\n\n/// Fetch the authenticated user's display name from the People API.\n/// Requires a token with the `profile` scope.\nasync fn fetch_profile_display_name(\n    client: &reqwest::Client,\n    token: &str,\n) -> Result<Option<String>, GwsError> {\n    let resp = crate::client::send_with_retry(|| {\n        client\n            .get(\"https://people.googleapis.com/v1/people/me\")\n            .query(&[(\"personFields\", \"names\")])\n            .bearer_auth(token)\n    })\n    .await\n    .map_err(|e| GwsError::Other(anyhow::anyhow!(\"People API request failed: {e}\")))?;\n\n    if !resp.status().is_success() {\n        let status = resp.status().as_u16();\n        let body = resp\n            .text()\n            .await\n            .unwrap_or_else(|_| \"(error body unreadable)\".to_string());\n        return Err(build_api_error(status, &body, \"People API request failed\"));\n    }\n\n    let body: Value = resp.json().await.map_err(|e| {\n        GwsError::Other(anyhow::anyhow!(\"Failed to parse People API response: {e}\"))\n    })?;\n\n    Ok(parse_profile_display_name(&body))\n}\n\n/// Extract the display name from a People API `people.get` response.","sourceCodeStart":637,"sourceCodeEnd":673,"githubUrl":"https://github.com/googleworkspace/cli/blob/a3768d0e82ad83cca2da97724e46bea4ff0e6dbd/crates/google-workspace-cli/src/helpers/gmail/mod.rs#L637-L673","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Verify egress: `curl -sS https://people.googleapis.com/` must connect (404/400 is fine, TLS failure is not).","Add people.googleapis.com to the proxy/firewall allowlist alongside gmail.googleapis.com.","Retry after restoring connectivity — profile display name is optional decoration and the command re-runs cleanly.","Check `GOOGLE_WORKSPACE_CLI_LOG=gws=debug` output to distinguish connect vs TLS vs DNS."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// The People API is a hidden dependency of gmail compose helpers — preflight both hosts\nfor host in [\"gmail.googleapis.com\", \"people.googleapis.com\"] {\n    if std::net::TcpStream::connect((host, 443)).is_err() {\n        return Err(anyhow::anyhow!(\"{host} unreachable — gmail helpers need both\"));\n    }\n}","typeGuard":null,"tryCatchPattern":"match fetch_profile_display_name(client, token).await {\n    // None (no names) is a valid Ok — only Err(GwsError::Other) transport failures warrant retry\n    Err(GwsError::Other(e)) if network_transient(&e) => {\n        tokio::time::sleep(Duration::from_secs(2)).await;\n        fetch_profile_display_name(client, token).await\n    }\n    other => other,\n}","preventionTips":["Allowlist people.googleapis.com alongside gmail.googleapis.com in firewalls/proxies.","Note display-name lookup requires the `profile` scope — grant it during `gws auth login` to avoid the sibling Api error.","Treat transport errors here as retryable decoration failures, not fatal compose blockers, in your own orchestration."],"tags":["people-api","network","reqwest","gmail","display-name"],"backgroundTag":"http-request-failed","analyzedSha":"a3768d0e82ad83cca2da97724e46bea4ff0e6dbd","analyzedAt":"2026-08-16T19:51:46.516Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}