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

  1. Simply re-run the triage command — a single transient failure is the top cause and retrying usually works.
  2. Verify connectivity to gmail.googleapis.com.
  3. 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).
  4. 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

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


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