router-for-me/CLIProxyAPI · error
auth provider refresh panic: %v
Error message
auth provider refresh panic: %v
What it means
This error comes from the panic guard around a plugin's AuthProvider.RefreshAuth capability. When a plugin's token-refresh handler panics, the host recovers it, fuses the plugin, and returns this error with handled=true, meaning the refresh was claimed by the plugin but failed. The existing auth is left untouched and will be retried or expired according to normal policy.
Source
Thrown at internal/pluginhost/auth_provider.go:347
}
func (h *Host) RefreshAuth(ctx context.Context, auth *coreauth.Auth) (refreshed *coreauth.Auth, handled bool, err error) {
if h == nil || auth == nil {
return nil, false, nil
}
record := h.authProviderRecord(authProvider(auth))
if record == nil || record.plugin.Capabilities.AuthProvider == nil {
return nil, false, nil
}
if !h.recordCurrent(*record) {
return nil, false, nil
}
defer func() {
if recovered := recover(); recovered != nil {
h.fusePlugin(record.id, "AuthProvider.RefreshAuth", recovered)
refreshed = nil
handled = true
err = fmt.Errorf("auth provider refresh panic: %v", 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: h.hostConfigSummary(),
HTTPClient: h.newHTTPClient(auth),
})
if errRefresh != nil {
return nil, true, errRefresh
}
data := pluginResp.Auth
if strings.TrimSpace(data.Provider) == "" {
data.Provider = authProvider(auth)View on GitHub (pinned to 78f0c4079e)
Solutions
- Read the fusePlugin log for 'AuthProvider.RefreshAuth' plus the recovered value to identify the plugin and panic cause.
- Check the stored auth file (auth dir) for the affected provider: malformed or version-skewed StorageJSON is the most common trigger.
- Re-authenticate the provider (delete the stale auth entry and redo login) so the plugin receives fresh, well-formed StorageJSON.
- Fix the plugin to validate StorageJSON (json.Unmarshal errors returned, not panicked) and nil-check Metadata/Attributes.
- Update the plugin to a version compatible with the current pluginapi.AuthRefreshRequest shape.
Example fix
// plugin side, before
func (p *Provider) RefreshAuth(ctx context.Context, req pluginapi.AuthRefreshRequest) (pluginapi.AuthRefreshResponse, error) {
var st stored
json.Unmarshal([]byte(req.StorageJSON), &st) // error ignored
return pluginapi.AuthRefreshResponse{AccessToken: st.Token.Value}, nil // panics if unmarshal failed
}
// after
func (p *Provider) RefreshAuth(ctx context.Context, req pluginapi.AuthRefreshRequest) (pluginapi.AuthRefreshResponse, error) {
var st stored
if err := json.Unmarshal([]byte(req.StorageJSON), &st); err != nil {
return pluginapi.AuthRefreshResponse{}, fmt.Errorf("refresh: decode storage: %w", err)
}
if st.Token.Value == "" {
return pluginapi.AuthRefreshResponse{}, fmt.Errorf("refresh: stored token is empty")
}
return pluginapi.AuthRefreshResponse{AccessToken: st.Token.Value}, nil
} Defensive patterns
Strategy: try-catch
Validate before calling
// Skip plugin refresh for providers whose auth storage is empty/malformed
if strings.TrimSpace(auth.StorageJSON()) == "" {
return nil, fmt.Errorf("auth %s has no storage blob; re-login required", auth.ID)
} Type guard
func refreshSafe(h *pluginhost.Host, auth coreauth.Auth) bool {
rec := h.AuthProviderRecord(auth.Provider())
return rec != nil && !h.IsPluginFused(rec.ID) && strings.TrimSpace(auth.StorageJSON()) != ""
} Try / catch
refreshed, handled, err := host.CallRefreshAuth(ctx, auth)
if err != nil {
if strings.Contains(err.Error(), "refresh panic") {
// handled=true: plugin claimed refresh but crashed; keep old auth and schedule re-login
log.WithError(err).Warn("plugin refresh panicked; retaining previous auth")
return auth, nil
}
return nil, err
} Prevention
- Validate plugin-written StorageJSON before relying on it for refresh.
- Re-login after plugin upgrades that change storage format.
- Alert on repeated fuse events for auth plugins so refreshes fail over to re-login early.
When it happens
Trigger: A background or on-demand token refresh for a provider served by a plugin whose RefreshAuth panics: invalid StorageJSON the plugin fails to parse defensively, unexpected nil Attributes/Metadata, or type assertion failures on cloned maps.
Common situations: A plugin whose stored credential format changed between versions (StorageJSON from an older auth file); auth files on disk written by a different plugin version; plugins that assume Metadata keys exist and dereference without checks.
Related errors
- auth provider panic: %v
- auth provider start login panic: %v
- auth provider poll login panic: %v
- auth provider refresh returned invalid auth data
- auth provider %s returned auth without provider
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/52349aadee79fbf8.
Report an issue: GitHub.