{"record":{"id":"8d9ec208b664e9b0","repo":"router-for-me/CLIProxyAPI","slug":"plugin-executor-s-http-request-panic-v","errorCode":null,"errorMessage":"plugin executor %s http request panic: %v","messagePattern":"plugin executor (.+?) http request panic: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/pluginhost/adapters_executors.go","lineNumber":799,"sourceCode":"\treturn coreexecutor.Response{\n\t\tPayload:  a.translateExecutorResponse(ctx, prepared, pluginResp.Payload, false, nil),\n\t\tMetadata: cloneAnyMap(pluginResp.Metadata),\n\t\tHeaders:  cloneHeader(pluginResp.Headers),\n\t}, nil\n}\n\nfunc (a *executorAdapter) HttpRequest(ctx context.Context, auth *coreauth.Auth, req *http.Request) (resp *http.Response, err error) {\n\tif a == nil || a.executor == nil || a.host.isPluginFused(a.pluginID) || !a.host.pluginIdentityCurrent(a.pluginID, a.path, a.version) {\n\t\treturn nil, fmt.Errorf(\"plugin executor %s is unavailable\", a.Identifier())\n\t}\n\tif req == nil {\n\t\treturn nil, fmt.Errorf(\"plugin executor %s received nil HTTP request\", a.Identifier())\n\t}\n\tdefer func() {\n\t\tif recovered := recover(); recovered != nil {\n\t\t\ta.host.fusePlugin(a.pluginID, \"Executor.HttpRequest\", recovered)\n\t\t\tresp = nil\n\t\t\terr = fmt.Errorf(\"plugin executor %s http request panic: %v\", a.Identifier(), recovered)\n\t\t}\n\t}()\n\tbody, errReadAll := readAndRestoreRequestBody(req)\n\tif errReadAll != nil {\n\t\treturn nil, fmt.Errorf(\"read plugin http request body: %w\", errReadAll)\n\t}\n\tpluginResp, errHTTPRequest := a.executor.HttpRequest(ctx, pluginapi.ExecutorHTTPRequest{\n\t\tAuthID:       authID(auth),\n\t\tAuthProvider: authProvider(auth),\n\t\tMethod:       req.Method,\n\t\tURL:          req.URL.String(),\n\t\tHeaders:      cloneHeader(req.Header),\n\t\tBody:         bytes.Clone(body),\n\t\tStorageJSON:  storageJSONFromAuth(auth),\n\t\tMetadata:     cloneAnyMap(authMetadata(auth)),\n\t\tAttributes:   authAttributes(auth),\n\t\tHTTPClient:   a.host.newHTTPClient(auth, a.provider),\n\t})","sourceCodeStart":781,"sourceCodeEnd":817,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/pluginhost/adapters_executors.go#L781-L817","documentation":"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'.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Check the recovered panic value in host logs and the Method/URL being proxied","Fix the plugin's HttpRequest to validate AuthID/Headers/StorageJSON before dereferencing and to return errors instead of panicking","Reinstall/reload the fixed plugin to clear the fuse","Add plugin-side tests for empty-auth and unsupported-method requests"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"resp, err := adapter.HttpRequest(ctx, auth, req)\nif err != nil {\n    if strings.Contains(err.Error(), \"http request panic\") {\n        return nil, status.Errorf(http.StatusBadGateway, \"plugin proxy failed\")\n    }\n    return nil, err\n}","preventionTips":["In plugins, validate ExecutorHTTPRequest fields (Headers, StorageJSON, Method) before use","Test plugin HTTP paths with anonymous auth and odd methods","Alert on 'http request panic' — the plugin is fused after the first occurrence"],"tags":["plugin","panic","http","circuit-breaker","recover"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}