fatedier/frp · error
send ${op} request to plugin error
Error message
send ${op} request to plugin error What it means
Returned by plugin.Manager.Handle in frps when any plugin in the chain returns an error from its Handle call while processing an operation (e.g. NewProxy, UserConn, Ping). The underlying per-plugin error is logged (logPluginError) but the returned error is deliberately generic, so the real cause is only visible in frps logs.
Source
Thrown at pkg/plugin/server/manager.go:94
if len(plugins) == 0 {
return content, nil
}
var (
res = &Response{
Reject: false,
Unchange: true,
}
retContent any
err error
)
ctx, xl := newPluginRequestContext()
for _, p := range plugins {
res, retContent, err = p.Handle(ctx, op, *content)
if err != nil {
logPluginError(xl, p, op, err, logMode)
return nil, errors.New("send " + op + " request to plugin error")
}
if res.Reject {
return nil, fmt.Errorf("%s", res.RejectReason)
}
if !res.Unchange {
// Preserve the existing Plugin contract: changed content must be *T.
// Buggy Plugin implementations still panic here, by design.
content = retContent.(*T)
}
}
return content, nil
}
func (m *Manager) Register(p Plugin) {
if p.IsSupport(OpLogin) {
m.loginPlugins = append(m.loginPlugins, p)
}
if p.IsSupport(OpNewProxy) {View on GitHub (pinned to 6c8a8d0a97)
Solutions
- Check frps logs for the logPluginError line — it contains the actual underlying error for the specific plugin and op
- Verify the plugin server is running and reachable at the configured addr from the frps host (curl the health/op endpoint)
- Validate the plugin's response JSON matches the frp plugin protocol for the op being processed
- If the error is transient (plugin restarting), ensure the plugin is healthy before clients reconnect
Example fix
# frps.toml — before [plugin.my-auth] addr = "http://127.0.0.1:9000" ops = ["Login"] # after — point at the address the plugin actually listens on [plugin.my-auth] addr = "http://10.0.0.5:9000" ops = ["Login"]
Defensive patterns
Strategy: try-catch
Validate before calling
// Before enabling a plugin, probe its endpoint from the frps host
resp, err := http.Get(pluginAddr + "/health") // or any documented route
if err != nil || resp.StatusCode >= 500 {
// do not enable the plugin until it is healthy
} Try / catch
// frps internal callers: capture the generic error, then consult logs
content, err := pluginManager.Handle(ctx, op, content)
if err != nil {
// underlying per-plugin error is in frps logs (logPluginError); match on op to triage
log.Warnf("plugin op %s failed: %v", op, err)
return err
} Prevention
- Run plugin health checks (or supervise the plugin process) so frps never routes ops to a dead plugin
- Pin plugin protocol versions when upgrading frp; test Login/NewProxy ops against a staging frps first
When it happens
Trigger: An HTTP plugin server configured in frps.toml [plugin.xxx] is unreachable, times out, or returns a malformed response; a built-in plugin (e.g. virtual_net) failing to initialize during the operation; plugin process crashing mid-request.
Common situations: Plugin HTTP server not started or wrong address/port in frps.toml; firewall blocking frps-to-plugin traffic; plugin response not matching the expected op schema; TLS mismatch between frps and the plugin endpoint.
Related errors
- no route found
- router config conflict
- group auth failed
- group params invalid
- group should have same remote port
AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15).
Data as JSON: /api/errors/f1a2f938c43adc3f.
Report an issue: GitHub.