googleworkspace/cli · error · GwsError
Failed to fetch user profile: {e}
Error message
Failed to fetch user profile: {e} What it means
Transport failure in `fetch_user_email` (reply.rs): `send_with_retry` could not complete `GET https://gmail.googleapis.com/gmail/v1/users/me/profile`, which `+reply-all` uses for self-dedup of recipients and self-reply detection. HTTP failures (401/403) go through `build_api_error`; this branch means no HTTP response at all after retries.
Source
Thrown at crates/google-workspace-cli/src/helpers/gmail/reply.rs:184
pub extra_to: Option<Vec<Mailbox>>,
pub cc: Option<Vec<Mailbox>>,
pub bcc: Option<Vec<Mailbox>>,
pub remove: Option<Vec<Mailbox>>,
pub html: bool,
pub attachments: Vec<Attachment>,
}
/// Fetch the authenticated user's primary email from the Gmail profile API.
/// Used in reply-all for self-dedup (excluding the user from recipients) and
/// self-reply detection (switching to original-To-based addressing).
async fn fetch_user_email(client: &reqwest::Client, token: &str) -> Result<String, GwsError> {
let resp = crate::client::send_with_retry(|| {
client
.get("https://gmail.googleapis.com/gmail/v1/users/me/profile")
.bearer_auth(token)
})
.await
.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}")))?;View on GitHub (pinned to a3768d0e82)
Solutions
- Restore connectivity and re-run the reply — no mail is sent until the final send call, so retry is safe.
- Verify `curl https://gmail.googleapis.com/` connects from the same shell (proxy env vars included).
- If behind an allowlisted firewall, keep gmail.googleapis.com on the list.
- Enable debug logs to see the underlying reqwest error kind.
Defensive patterns
Strategy: retry
Try / catch
// fetch_user_email only fails fatally at transport level; retry with backoff before giving up on reply-all
let email = match fetch_user_email(client, token).await {
Ok(e) => e,
Err(GwsError::Other(e)) if e.to_string().contains("Failed to fetch user profile") => {
tokio::time::sleep(Duration::from_secs(2)).await;
fetch_user_email(client, token).await?
}
Err(e) => return Err(e),
}; Prevention
- Reply-all makes one extra profile call — ensure gmail.googleapis.com is reachable before scripting it.
- No mail is sent before the final send call, so retrying the whole command is always safe.
- Distinguish transport (this) from auth (GwsError::Api with 401/403) failures when scripting exit-code handling.
When it happens
Trigger: Running `gws gmail +reply-all` offline; DNS/proxy failure to gmail.googleapis.com; connection resets persisting across the whole retry budget.
Common situations: Same network-class issues as other gmail helper calls, but noticed specifically during reply-all because that is the only flow that fetches the profile.
Related errors
- Failed to fetch message: {e}
- Failed to fetch sendAs settings: {e}
- People API request failed: {e}
- Failed to fetch attachment: {e}
- Pub/Sub pull failed: {e}
AI-assisted analysis of googleworkspace/cli@a3768d0e82 (2026-08-16).
Data as JSON: /api/errors/5497cd21cdc6ea9e.
Report an issue: GitHub.