docker/cli · warning
credentials erased successfully, but there was a failure to…
Error message
credentials erased successfully, but there was a failure to revoke the OAuth refresh token with the tenant: %w
What it means
Returned by OAuthManager.Logout after eraseTokensFromStore succeeded but RevokeToken (POST <TenantURL>/oauth/revoke) failed. Locally stored tokens are gone, but the tenant still considers the refresh token valid. The error is wrapped with %w so callers can see the revoke failure reason.
Solutions
- Accept the warning if local erasure is sufficient for your threat model (token will expire at tenant naturally).
- If you must revoke, manually revoke via the Hub UI (revoke the token/session).
- Check network/proxy to /oauth/revoke and retry logout only if a token is still stored.
Example fix
# before docker logout # -> credentials erased successfully, but revoke failed # after: token is gone locally; revoke from Hub UI # hub.docker.com -> Account Settings -> Security -> revoke the session # (or ignore; the refresh token will expire per tenant policy)
Defensive patterns
Strategy: fallback
Try / catch
// erase succeeded; revoke failed -> treat as soft warning
if strings.Contains(err.Error(), "credentials erased successfully") { log.Warn(err); return nil } Prevention
- Treat local erasure as the primary logout guarantee.
- Provide a UI path to revoke outstanding tokens.
- Document that the refresh token expires at the tenant on its own.
When it happens
Trigger: Logout reaches the revoke step with a network/TLS/HTTP failure (non-200 from /oauth/revoke, or transport error). Because erase already happened, a retry needs a stored token that no longer exists.
Common situations: Transient network blip or tenant outage at the exact revoke call; corporate proxy blocking /oauth/revoke; the refresh token already expired at the tenant so revoke 400s.
Related errors
- failed to get tokens
- failed to erase tokens
- failed to decode response
- unexpected response from Hub
- failed waiting for authentication
AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07).
Data as JSON: /api/errors/bd054f6c4e6f22d0.
Report an issue: GitHub.
Appendix: source
Thrown at internal/oauth/manager/manager.go:184
if err != nil {
return err
}
if refreshConfig.Password == "" {
return nil
}
parts := strings.Split(refreshConfig.Password, "..")
if len(parts) != 2 {
// the token wasn't stored by the CLI, so don't revoke it
// or erase it from the store/error
return nil
}
// erase the token from the store first, that way
// if the revoke fails, the user can try to logout again
if err := m.eraseTokensFromStore(); err != nil {
return fmt.Errorf("failed to erase tokens: %w", err)
}
if err := m.api.RevokeToken(ctx, parts[0]); err != nil {
return fmt.Errorf("credentials erased successfully, but there was a failure to revoke the OAuth refresh token with the tenant: %w", err)
}
return nil
}
const (
accessTokenKey = registry.IndexServer + "access-token"
refreshTokenKey = registry.IndexServer + "refresh-token"
)
func (m *OAuthManager) storeTokensInStore(tokens api.TokenResponse, username string) error {
return errors.Join(
m.store.Store(types.AuthConfig{
Username: username,
Password: tokens.AccessToken,
ServerAddress: accessTokenKey,
}),
m.store.Store(types.AuthConfig{
Username: username,View on GitHub (pinned to 4f84911bfe)