router-for-me/CLIProxyAPI · error

plugin executor %s http request panic: %v

Error message

plugin executor %s http request panic: %v

What it means

The plugin's HttpRequest implementation panicked; the adapter's deferred recover() converted the panic into an error, nils the response, and fuses the plugin so later calls fail fast with 'unavailable'.

Source

Thrown at internal/pluginhost/adapters_executors.go:799

	return coreexecutor.Response{
		Payload:  a.translateExecutorResponse(ctx, prepared, pluginResp.Payload, false, nil),
		Metadata: cloneAnyMap(pluginResp.Metadata),
		Headers:  cloneHeader(pluginResp.Headers),
	}, nil
}

func (a *executorAdapter) HttpRequest(ctx context.Context, auth *coreauth.Auth, req *http.Request) (resp *http.Response, 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())
	}
	if req == nil {
		return nil, fmt.Errorf("plugin executor %s received nil HTTP request", a.Identifier())
	}
	defer func() {
		if recovered := recover(); recovered != nil {
			a.host.fusePlugin(a.pluginID, "Executor.HttpRequest", recovered)
			resp = nil
			err = fmt.Errorf("plugin executor %s http request panic: %v", a.Identifier(), recovered)
		}
	}()
	body, errReadAll := readAndRestoreRequestBody(req)
	if errReadAll != nil {
		return nil, fmt.Errorf("read plugin http request body: %w", errReadAll)
	}
	pluginResp, errHTTPRequest := a.executor.HttpRequest(ctx, pluginapi.ExecutorHTTPRequest{
		AuthID:       authID(auth),
		AuthProvider: authProvider(auth),
		Method:       req.Method,
		URL:          req.URL.String(),
		Headers:      cloneHeader(req.Header),
		Body:         bytes.Clone(body),
		StorageJSON:  storageJSONFromAuth(auth),
		Metadata:     cloneAnyMap(authMetadata(auth)),
		Attributes:   authAttributes(auth),
		HTTPClient:   a.host.newHTTPClient(auth, a.provider),
	})

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. Check the recovered panic value in host logs and the Method/URL being proxied
  2. Fix the plugin's HttpRequest to validate AuthID/Headers/StorageJSON before dereferencing and to return errors instead of panicking
  3. Reinstall/reload the fixed plugin to clear the fuse
  4. Add plugin-side tests for empty-auth and unsupported-method requests
Defensive patterns

Strategy: try-catch

Try / catch

resp, err := adapter.HttpRequest(ctx, auth, req)
if err != nil {
    if strings.Contains(err.Error(), "http request panic") {
        return nil, status.Errorf(http.StatusBadGateway, "plugin proxy failed")
    }
    return nil, err
}

Prevention

When it happens

Trigger: Calling HttpRequest where the plugin panics — e.g. it dereferences fields of the ExecutorHTTPRequest struct it expects to be set (Headers map, StorageJSON) or mishandles a request method/URL it does not support.

Common situations: Plugin assumes auth data exists (StorageJSON empty for anonymous requests); plugin built against an older plugin API struct; unusual HTTP method or header shape reaching the plugin.

Related errors


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