{"record":{"id":"4d2f2f9420d90865","repo":"router-for-me/CLIProxyAPI","slug":"resource-handler-panic-v","errorCode":null,"errorMessage":"resource handler panic: %v","messagePattern":"resource handler panic: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/pluginhost/management.go","lineNumber":359,"sourceCode":"}\n\nfunc escapeManagementResponseBody(resp pluginapi.ManagementResponse) []byte {\n\tbody, okEscaped := htmlsanitize.JSONBodyIfLikely(resp.Body, resp.Headers.Get(\"Content-Type\"))\n\tif !okEscaped {\n\t\treturn resp.Body\n\t}\n\treturn body\n}\n\nfunc (h *Host) callResourceHandler(ctx context.Context, record resourceRouteRecord, req pluginapi.ManagementRequest) (resp pluginapi.ManagementResponse, err error) {\n\tif h == nil || record.route.Handler == nil || h.isPluginFused(record.pluginID) || !h.pluginIdentityCurrent(record.pluginID, record.path, record.version) {\n\t\treturn pluginapi.ManagementResponse{}, nil\n\t}\n\tdefer func() {\n\t\tif recovered := recover(); recovered != nil {\n\t\t\th.fusePlugin(record.pluginID, \"ResourceHandler.HandleManagement\", recovered)\n\t\t\tresp = pluginapi.ManagementResponse{}\n\t\t\terr = fmt.Errorf(\"resource handler panic: %v\", recovered)\n\t\t}\n\t}()\n\treturn record.route.Handler.HandleManagement(ctx, req)\n}\n","sourceCodeStart":341,"sourceCodeEnd":364,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/pluginhost/management.go#L341-L364","documentation":"Identical recovery wrapper for plugin resource routes (mounted under the resource plugin base path): a panicking HandleManagement in a resource handler is caught, the plugin is fused, and this error is returned. Keeps panics in resource endpoints from crashing the host process.","triggerScenarios":"A request to a plugin's resource endpoint (resourcePluginBasePath/<pluginID>/...) triggers a panic inside the plugin's resource handler.","commonSituations":"Resource handlers parsing user-supplied subpaths or bodies without validation; plugins sharing state with management handlers and racing on reload.","solutions":["Fix the panic in the plugin's resource handler; inspect the recovered value in the error message","Add input validation and a top-level defer/recover inside the plugin handler to convert panics into 500 responses","Disable the resource route or plugin until fixed, and restart the server to clear the fuse"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"resp, err := h.callResourceHandler(ctx, record, req)\nif err != nil {\n    log.WithError(err).WithField(\"plugin\", record.pluginID).Error(\"resource handler failed\")\n    return http.StatusInternalServerError, []byte(\"plugin resource handler failed\")\n}","preventionTips":["Validate subpath parsing in resource handlers; guard slice/array indexing","Add a top-level recover() in the plugin handler converting panics into 500 responses","Note that after a fuse the plugin needs a reload/restart to serve again"],"tags":["plugin","panic","resource-routes","http-handler","isolation"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}