googleworkspace/cli · error
Token response contained no access token
Error message
Token response contained no access token
What it means
After yup_oauth2::AuthorizedUserAuthenticator (with EncryptedTokenStorage as its cache) returns from token(scopes), the code calls Token::token() to extract the access token string. This error fires when the token operation succeeded but the returned Token has no access_token set — i.e. a token object that exists yet carries no usable bearer credential. It is thrown by gws itself as an anyhow error, not by yup-oauth2.
Source
Thrown at crates/google-workspace-cli/src/auth.rs:273
&secret.client_secret,
&secret.refresh_token,
)
.await;
}
// No proxy - use yup-oauth2 (faster, has token caching)
let auth = yup_oauth2::AuthorizedUserAuthenticator::builder(secret.clone())
.with_storage(Box::new(crate::token_storage::EncryptedTokenStorage::new(
token_cache_path.to_path_buf(),
)))
.build()
.await
.context("Failed to build authorized user authenticator")?;
let token = auth.token(scopes).await.context("Failed to get token")?;
Ok(token
.token()
.ok_or_else(|| anyhow::anyhow!("Token response contained no access token"))?
.to_string())
}
Credential::ServiceAccount(key) => {
let tc_filename = token_cache_path
.file_name()
.map(|f| f.to_string_lossy().to_string())
.unwrap_or_else(|| "token_cache.json".to_string());
let sa_cache = token_cache_path.with_file_name(format!("sa_{tc_filename}"));
let builder = yup_oauth2::ServiceAccountAuthenticator::builder(key).with_storage(
Box::new(crate::token_storage::EncryptedTokenStorage::new(sa_cache)),
);
let auth = builder
.build()
.await
.context("Failed to build service account authenticator")?;
let token = auth.token(scopes).await.context("Failed to get token")?;View on GitHub (pinned to a3768d0e82)
Solutions
- Run `gws auth logout && gws auth login` — this clears and rebuilds the token cache
- If logout fails, manually delete the token cache file (e.g. ~/.config/gws/token_cache.json) and log in again
- Upgrade gws to the latest release so its cache schema matches the yup-oauth2 version in use
Defensive patterns
Strategy: try-catch
Try / catch
match get_token(&scopes).await {
Ok(t) => { /* proceed */ }
Err(e) if e.to_string().contains("no access token") => {
// treat cache as poisoned: clear token cache and force interactive re-login
}
Err(e) => { /* other auth failure */ }
} Prevention
- Treat the gws token cache as disposable state — any anomaly, delete and re-login
- Do not sync or hand-edit files under ~/.config/gws
- Upgrade gws regularly so the yup-oauth2 cache format stays in sync
When it happens
Trigger: The encrypted token cache file decrypted to a structurally valid but semantically empty entry (no access_token field); yup-oauth2 returned an unauthenticated/error token because the cached refresh material is unusable; a yup-oauth2 version upgrade changed the cached Token shape so old cache data deserializes without the access_token.
Common situations: Token cache under ~/.config/gws restored from a backup of another machine or hand-edited; partial cache write from an old gws version; downgraded gws/yup-oauth2 reading a cache written by a newer version.
Related errors
- Token refresh failed with status {}: {}
- Failed to write client config: {e}
- Cannot read {}: {e}
- Invalid client_secret.json format: {e}
- No credentials found. Run `gws auth setup` to configure, `gw
AI-assisted analysis of googleworkspace/cli@a3768d0e82 (2026-08-16).
Data as JSON: /api/errors/951d24276bc723b3.
Report an issue: GitHub.