googleworkspace/cli · error · GwsError
5
5
Error message
Failed to list messages: {e} What it means
In `+triage` (triage.rs), the initial `GET /gmail/v1/users/me/messages?q=...&maxResults=...` failed at the transport level (`client.get(...).send()` — note: no `send_with_retry` wrapper, unlike other gmail helpers, so the FIRST transient error aborts). This is a reqwest send error: DNS, connect, TLS, or mid-request disconnect. HTTP failures take the `GwsError::Api { reason: "list_failed" }` branch instead.
Source
Thrown at crates/google-workspace-cli/src/helpers/gmail/triage.rs:59
// gmail.metadata scope. When a token carries both metadata and modify
// scopes the API may resolve to the metadata path and reject `q` with 403.
// gmail.readonly always supports `q`.
let token = auth::get_token(&[GMAIL_READONLY_SCOPE])
.await
.map_err(|e| GwsError::Auth(format!("Gmail auth failed: {e}")))?;
let client = crate::client::build_client()?;
// 1. List message IDs
let list_url = "https://gmail.googleapis.com/gmail/v1/users/me/messages";
let list_resp = client
.get(list_url)
.query(&[("q", query), ("maxResults", &max.to_string())])
.bearer_auth(&token)
.send()
.await
.map_err(|e| GwsError::Other(anyhow::anyhow!("Failed to list messages: {e}")))?;
if !list_resp.status().is_success() {
let err = list_resp.text().await.unwrap_or_default();
return Err(GwsError::Api {
code: 0,
message: err,
reason: "list_failed".to_string(),
enable_url: None,
});
}
let list_json: Value = list_resp
.json()
.await
.map_err(|e| GwsError::Other(anyhow::anyhow!("Failed to parse list response: {e}")))?;
let messages = match list_json.get("messages").and_then(|m| m.as_array()) {
Some(m) => m,View on GitHub (pinned to a3768d0e82)
Solutions
- Simply re-run the triage command — a single transient failure is the top cause and retrying usually works.
- Verify connectivity to gmail.googleapis.com.
- If triage repeatedly fails while `gws gmail users.messages list` works, this confirms the no-retry gap; update the CLI or patch triage.rs to use `crate::client::send_with_retry` like mod.rs does (see example fix).
- Check proxy env vars in the shell running gws.
Example fix
// before: single-shot send, no retry
let list_resp = client
.get(list_url)
.query(&[("q", query), ("maxResults", &max.to_string())])
.bearer_auth(&token)
.send()
.await
.map_err(|e| GwsError::Other(anyhow::anyhow!("Failed to list messages: {e}")))?;
// after: use the shared retry helper like the other gmail helpers
let list_resp = crate::client::send_with_retry(|| {
client
.get(list_url)
.query(&[("q", query), ("maxResults", &max.to_string())])
.bearer_auth(&token)
})
.await
.map_err(|e| GwsError::Other(anyhow::anyhow!("Failed to list messages: {e}")))?; Defensive patterns
Strategy: retry
Validate before calling
// Unlike sibling helpers, +triage's list call is single-shot — wrap your invocations with retry
for attempt in 0..3 {
match run_triage(&args).await {
Err(e) if is_transport_error(&e) && attempt < 2 => sleep_backoff(attempt).await,
other => return other,
}
} Type guard
fn is_transport_error(e: &GwsError) -> bool {
matches!(e, GwsError::Other(_)) && e.to_string().starts_with("Failed to list messages")
} Try / catch
// Inside a patched triage.rs, replace the single-shot send with the shared retry helper:
let list_resp = crate::client::send_with_retry(|| {
client.get(list_url).query(&[("q", query), ("maxResults", &max.to_string())]).bearer_auth(&token)
}).await.map_err(|e| GwsError::Other(anyhow::anyhow!("Failed to list messages: {e}")))?; Prevention
- Expect zero-retry behavior from +triage's initial list call — a single blip aborts; just re-run.
- In scripts driving +triage, add your own retry-with-backoff around the command.
- Contributors: route every googleapis call through crate::client::send_with_retry for uniform retry semantics.
When it happens
Trigger: Running `gws gmail +triage` with a momentary network blip — because there is no retry, even a single dropped connection fails the whole triage session; offline runs; proxy blocking gmail.googleapis.com.
Common situations: Interactive triage over wifi where each keypress fetches messages; any environment where the other helpers survive thanks to send_with_retry but +triage dies on the first hiccup.
Related errors
- Failed to fetch message: {e}
- Failed to fetch sendAs settings: {e}
- People API request failed: {e}
- Failed to fetch attachment: {e}
- Failed to fetch user profile: {e}
AI-assisted analysis of googleworkspace/cli@a3768d0e82 (2026-08-16).
Data as JSON: /api/errors/906422f4ff113630.
Report an issue: GitHub.