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

  1. Run `gws auth logout && gws auth login` — this clears and rebuilds the token cache
  2. If logout fails, manually delete the token cache file (e.g. ~/.config/gws/token_cache.json) and log in again
  3. 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

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


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