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

  1. Inspect the recovered panic value (%v) in host logs and the AuthID/AuthProvider being refreshed
  2. Fix the plugin's RefreshAuth to handle the exact StorageJSON/Metadata it receives (validate before dereferencing)
  3. Reinstall/reload the fixed plugin to clear the fuse and retry refresh
  4. 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

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


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