router-for-me/CLIProxyAPI · error
plugin executor %s refresh panic: %v
Error message
plugin executor %s refresh panic: %v
What it means
The plugin's AuthProvider.RefreshAuth capability panicked and the adapter's deferred recover() converted it into an error. The host also fuses the plugin (record.id) so later calls fail fast, and the refresh returns no credentials.
Source
Thrown at internal/pluginhost/adapters_executors.go:700
return &coreexecutor.StreamResult{
Headers: cloneHeader(pluginResp.Headers),
Chunks: mapExecutorStreamChunks(ctx, a.translateExecutorStreamChunks(ctx, prepared, pluginResp.Chunks)),
}, nil
}
func (a *executorAdapter) Refresh(ctx context.Context, auth *coreauth.Auth) (refreshed *coreauth.Auth, err error) {
if a == nil || a.executor == nil || a.host.isPluginFused(a.pluginID) || !a.host.pluginIdentityCurrent(a.pluginID, a.path, a.version) {
return nil, fmt.Errorf("plugin executor %s is unavailable", a.Identifier())
}
record := a.host.authProviderRecord(authProvider(auth))
if record == nil || record.plugin.Capabilities.AuthProvider == nil {
return auth.Clone(), nil
}
defer func() {
if recovered := recover(); recovered != nil {
a.host.fusePlugin(record.id, "AuthProvider.RefreshAuth", recovered)
refreshed = nil
err = fmt.Errorf("plugin executor %s refresh panic: %v", a.Identifier(), recovered)
}
}()
pluginResp, errRefresh := record.plugin.Capabilities.AuthProvider.RefreshAuth(ctx, pluginapi.AuthRefreshRequest{
AuthID: authID(auth),
AuthProvider: authProvider(auth),
StorageJSON: storageJSONFromAuth(auth),
Metadata: cloneAnyMap(authMetadata(auth)),
Attributes: authAttributes(auth),
Host: a.host.hostConfigSummary(),
HTTPClient: a.host.newHTTPClient(auth),
})
if errRefresh != nil {
return nil, errRefresh
}
data := pluginResp.Auth
if strings.TrimSpace(data.Provider) == "" {
data.Provider = authProvider(auth)View on GitHub (pinned to 78f0c4079e)
Solutions
- Inspect the recovered panic value (%v) in host logs and the AuthID/AuthProvider being refreshed
- Fix the plugin's RefreshAuth to handle the exact StorageJSON/Metadata it receives (validate before dereferencing)
- Reinstall/reload the fixed plugin to clear the fuse and retry refresh
- As a workaround, re-run the OAuth login flow for that provider so fresh auth data replaces the input that triggers the panic
Defensive patterns
Strategy: try-catch
Try / catch
refreshed, err := adapter.Refresh(ctx, auth)
if err != nil {
if strings.Contains(err.Error(), "refresh panic") {
// plugin fused; fall back to re-auth or another credential
return reauthenticate(auth)
}
return nil, err
} Prevention
- Fuzz plugin refresh handlers with empty/expired/malformed StorageJSON before shipping
- Never hand-edit auth JSON files that plugins consume
- Keep an unauthenticated-retry or re-login path for each plugin provider
When it happens
Trigger: Calling executorAdapter.Refresh when the plugin exposes an AuthProvider capability and its RefreshAuth function panics — e.g. malformed StorageJSON, expired token shape it does not expect, or a nil map/slice dereference in the plugin's refresh logic.
Common situations: Custom OAuth provider plugin with a buggy refresh handler; token storage schema drift between plugin versions; auth file manually edited so Metadata/StorageJSON no longer parses into the plugin's expected struct.
Related errors
- plugin executor %s stream panic: %v
- plugin executor %s refresh returned invalid auth data
- plugin executor %s count tokens panic: %v
- plugin executor %s http request panic: %v
- auth provider panic: %v
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/a21738fbe4c5b964.
Report an issue: GitHub.