router-for-me/CLIProxyAPI · error

plugin auth provider refresh is unavailable for provider %s

Error message

plugin auth provider refresh is unavailable for provider %s

What it means

The plugin-based auth refresh compatibility executor cannot refresh a credential: neither the home provider nor the plugin host handled the refresh, yet the auth carries a refresh_token in its Metadata. internal/pluginhost/plugin_refresh_compat_executor.go then returns this error naming the provider instead of silently returning a stale credential, so callers know re-login is required.

Source

Thrown at internal/pluginhost/plugin_refresh_compat_executor.go:135

		return nil, fmt.Errorf("plugin refresh compat executor is unavailable")
	}
	if ctx == nil {
		ctx = context.Background()
	}
	if refreshed, handled, errHome := helps.RefreshAuthViaHome(ctx, e.cfg, auth); handled {
		return refreshed, errHome
	}
	if e.host != nil {
		if refreshed, handled, errRefresh := e.host.RefreshAuth(ctx, auth); handled {
			return refreshed, errRefresh
		}
	}
	if authHasRefreshToken(auth) {
		provider := e.Identifier()
		if provider == "" && auth != nil {
			provider = strings.TrimSpace(auth.Provider)
		}
		return nil, fmt.Errorf("plugin auth provider refresh is unavailable for provider %s", provider)
	}
	if auth == nil {
		return nil, nil
	}
	return auth.Clone(), nil
}

func authHasRefreshToken(auth *coreauth.Auth) bool {
	if auth == nil || auth.Metadata == nil {
		return false
	}
	if token, _ := auth.Metadata["refresh_token"].(string); strings.TrimSpace(token) != "" {
		return true
	}
	if token, _ := auth.Metadata["refreshToken"].(string); strings.TrimSpace(token) != "" {
		return true
	}
	return false

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. Re-run the OAuth/login flow for that provider to mint fresh credentials (the refresh token has no usable path here)
  2. Install/enable the plugin that owns the provider so host.RefreshAuth can handle it
  3. Remove the stale auth file from auths/ if the provider is no longer used
  4. Verify the provider identifier in the error matches an executor/plugin you actually ship
Defensive patterns

Strategy: fallback

Validate before calling

if authHasRefreshToken(auth) {
    if _, handled, _ := host.RefreshAuth(ctx, auth); !handled {
        // no plugin can refresh this: route the user to re-login now
    }
}

Try / catch

refreshed, err := executor.RefreshAuth(ctx, auth)
if err != nil && strings.Contains(err.Error(), "refresh is unavailable") {
    log.Warnf("credential for %s cannot be refreshed; starting interactive login", auth.Provider)
    return beginLoginFlow(ctx, auth.Provider)
}

Prevention

When it happens

Trigger: RefreshAuth is invoked on an Auth whose Metadata['refresh_token'] is non-empty, the plugin backing that provider is not loaded/disabled/does not implement refresh, and the built-in executor registry has no handler for it either.

Common situations: Plugin binary missing or removed after the credential was issued; plugin version that lacks a refresh implementation; provider disabled in config but old auth file still present in auths/; auth imported from another installation whose provider plugin is not installed.

Related errors


AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15). Data as JSON: /api/errors/2d4207fca80fba6f. Report an issue: GitHub.