docker/cli · error

failed to erase tokens

Error message

failed to erase tokens: %w

What it means

Returned by OAuthManager.Logout when eraseTokensFromStore() fails. During logout the manager first erases the stored access/refresh tokens; if the credential store rejects the erase (Erase/Save), logout aborts with the wrapped error before attempting revoke.

Solutions

  1. Unlock/repair the credential store (unlock keychain, reinstall helper).
  2. Ensure ~/.docker/config.json is writable.
  3. Re-run `docker logout`.
  4. As a last resort, manually remove the entries from config.json / keyring.

Example fix

# before: logout fails erasing
docker logout  # -> failed to erase tokens
unlock-keychain
sudo apt-get install docker-credential-pass
docker logout
Defensive patterns

Strategy: try-catch

Validate before calling

// verify the store can erase before relying on logout
if err := store.Erase(refreshTokenKey); err != nil { /* fix store first */ }

Try / catch

if strings.Contains(err.Error(), "failed to erase tokens") { repairStore(); retry logout }

Prevention

When it happens

Trigger: The credential helper Erase call or config.json rewrite fails: locked keyring, helper binary missing, permission denied on ~/.docker/config.json.

Common situations: Keyring locked at logout time; helper removed since login; file permissions changed; disk full / read-only.

Related errors


AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07). Data as JSON: /api/errors/36ab2b3727a8e9eb. Report an issue: GitHub.

Appendix: source

Thrown at internal/oauth/manager/manager.go:181

// returned.
func (m *OAuthManager) Logout(ctx context.Context) error {
	refreshConfig, err := m.store.Get(refreshTokenKey)
	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,

View on GitHub (pinned to 4f84911bfe)