router-for-me/CLIProxyAPI · error

auth provider poll login panic: %v

Error message

auth provider poll login panic: %v

What it means

This error is raised by the panic guard around a plugin's AuthProvider.PollLogin capability. If a plugin's poll-stage login handler panics while completing an OAuth-style flow, the host recovers it, fuses the plugin, and returns this error instead of crashing the process. The panic originated in plugin code, and the poll is treated as unhandled.

Source

Thrown at internal/pluginhost/auth_provider.go:314

	}
	var pollMetadata map[string]any
	if len(metadata) > 0 {
		pollMetadata = metadata[0]
	}
	return h.callPollLogin(ctx, *record, provider, state, pollMetadata)
}

func (h *Host) callPollLogin(ctx context.Context, record capabilityRecord, provider, state string, metadata map[string]any) (resp pluginapi.AuthLoginPollResponse, handled bool, err error) {
	authProvider := record.plugin.Capabilities.AuthProvider
	if h == nil || authProvider == nil || h.isPluginFused(record.id) || !h.recordCurrent(record) {
		return pluginapi.AuthLoginPollResponse{}, false, nil
	}
	defer func() {
		if recovered := recover(); recovered != nil {
			h.fusePlugin(record.id, "AuthProvider.PollLogin", recovered)
			resp = pluginapi.AuthLoginPollResponse{}
			handled = false
			err = fmt.Errorf("auth provider poll login panic: %v", recovered)
		}
	}()
	req := pluginapi.AuthLoginPollRequest{
		Provider:   normalizeProviderID(provider),
		State:      strings.TrimSpace(state),
		Host:       h.hostConfigSummary(),
		HTTPClient: h.newHTTPClient(nil),
		Metadata:   cloneAnyMap(metadata),
	}
	resp, errPoll := authProvider.PollLogin(ctx, req)
	if errPoll != nil {
		return pluginapi.AuthLoginPollResponse{}, true, errPoll
	}
	return resp, true, nil
}

func (h *Host) RefreshAuth(ctx context.Context, auth *coreauth.Auth) (refreshed *coreauth.Auth, handled bool, err error) {
	if h == nil || auth == nil {

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. Inspect the fusePlugin log entry for 'AuthProvider.PollLogin' and the recovered value to pinpoint the panicking plugin.
  2. Verify the state and metadata you pass to the poll endpoint are exactly what the plugin's StartLogin returned (do not re-serialize or trim them yourself).
  3. Run the plugin's PollLogin standalone with the same State/Metadata to capture the full stack trace.
  4. Fix or update the plugin so PollLogin validates inputs and returns errors; add nil checks for Metadata map access.
  5. Restart the host to clear the fuse after fixing the plugin.

Example fix

// plugin side, before
func (p *Provider) PollLogin(ctx context.Context, req pluginapi.AuthLoginPollRequest) (pluginapi.AuthLoginPollResponse, error) {
	parts := strings.Split(req.State, ":")
	return pluginapi.AuthLoginPollResponse{Token: parts[1]}, nil // panics: index out of range
}

// after
func (p *Provider) PollLogin(ctx context.Context, req pluginapi.AuthLoginPollRequest) (pluginapi.AuthLoginPollResponse, error) {
	parts := strings.Split(req.State, ":")
	if len(parts) != 2 {
		return pluginapi.AuthLoginPollResponse{}, fmt.Errorf("poll login: malformed state")
	}
	return pluginapi.AuthLoginPollResponse{Token: parts[1]}, nil
}
Defensive patterns

Strategy: try-catch

Validate before calling

if strings.TrimSpace(state) == "" {
    return fmt.Errorf("poll login requires the state returned by start login")
}

Type guard

func validPollInput(state string, metadata map[string]any) bool {
    return strings.TrimSpace(state) != "" && metadata != nil
}

Try / catch

resp, handled, err := host.CallPollLogin(ctx, provider, state, metadata)
if err != nil {
    if strings.Contains(err.Error(), "poll login panic") {
        log.WithField("provider", provider).WithError(err).Error("plugin crashed during poll; user must restart login")
    }
    return err
}
if !handled {
    // plugin gone (fused/removed): restart the login flow from start
}

Prevention

When it happens

Trigger: Polling login completion for a plugin-backed provider (state + metadata passed from the start-login response) when the plugin's PollLogin panics: nil State string assumptions, malformed state parsing, type assertions on Metadata values, or nil HTTPClient usage.

Common situations: A plugin that expects the state token in a specific format but receives a trimmed/empty state (host applies strings.TrimSpace before passing); plugin written for a different poll response schema; partially completed login where metadata from StartLogin was lost.

Related errors


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