googleworkspace/cli · error · GwsError
Profile missing emailAddress
Error message
Profile missing emailAddress
What it means
The profile JSON parsed but `emailAddress` was absent or not a string — `profile.get("emailAddress").and_then(|v| v.as_str())` returned None. The Gmail profile endpoint guarantees `emailAddress` for a valid token with gmail scope, so this implies the endpoint returned something else: an empty object from a scope mismatch, an error envelope with 200, a stub response, or a future API change.
Source
Thrown at crates/google-workspace-cli/src/helpers/gmail/reply.rs:208
.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}")))?;
profile
.get("emailAddress")
.and_then(|v| v.as_str())
.map(|s| s.to_string())
.ok_or_else(|| GwsError::Other(anyhow::anyhow!("Profile missing emailAddress")))
}
// --- Message construction ---
fn extract_reply_to_address(original: &OriginalMessage) -> Vec<Mailbox> {
match &original.reply_to {
Some(reply_to) => reply_to.clone(),
None => vec![original.from.clone()],
}
}
fn build_reply_all_recipients(
original: &OriginalMessage,
extra_cc: Option<&[Mailbox]>,
remove: Option<&[Mailbox]>,
self_email: Option<&str>,
from_alias: Option<&str>,
) -> Result<ReplyRecipients, GwsError> {View on GitHub (pinned to a3768d0e82)
Solutions
- Verify scopes: run `gws auth status` and ensure gmail scope is granted, then `gws gmail users.getProfile --userId me` to inspect the live response.
- If a stub server is in play, add `emailAddress` to the fixture.
- Re-auth (`gws auth login`) if scopes are wrong or partial.
- Update the CLI if Gmail changed the profile shape.
Defensive patterns
Strategy: type-guard
Validate before calling
// Check scope coverage before reply-all runs: a token without gmail scope yields degenerate profiles
fn token_has_gmail_scope(scopes: &[String]) -> bool {
scopes.iter().any(|s| s.contains("gmail"))
} Type guard
fn profile_has_email(v: &serde_json::Value) -> bool {
v.get("emailAddress").and_then(|e| e.as_str()).is_some_and(|s| !s.is_empty())
} Try / catch
// Validate the envelope shape right after parse; fail with a scope-hint message:
let profile: Value = resp.json().await?;
if !profile_has_email(&profile) {
return Err(anyhow::anyhow!("profile lacks emailAddress — token may be missing gmail scope; run gws auth login"));
} Prevention
- Run `gws gmail users.getProfile --userId me` once after auth to confirm the token yields a full profile.
- Grant gmail scopes at `gws auth login`; re-login after scope changes.
- Type-guard API envelopes before extracting required fields in your own Google API code.
When it happens
Trigger: OAuth token granted for the wrong product (e.g. only People scope) causing a degenerate profile response; a mock server returning `{}`; API contract drift; a delegated/service account context where the profile resolves to an empty object.
Common situations: Scripts reusing a token minted for a different scope set; test fixtures that stub the profile endpoint minimally; rarely, Gmail API schema evolution.
Related errors
- Attachment response missing 'data' field for {attachment_id}
- Failed to fetch user profile: {e}
- Failed to parse profile: {e}
- Message is missing From header
- Message is missing Message-ID header
AI-assisted analysis of googleworkspace/cli@a3768d0e82 (2026-08-16).
Data as JSON: /api/errors/0b5d90d1f74d96b8.
Report an issue: GitHub.