fatedier/frp · warning
send CloseProxy request to plugin errors: %s
Error message
send CloseProxy request to plugin errors: %s
What it means
One or more CloseProxy-aware server plugins failed to handle the OpCloseProxy request (transport error or non-200 from p.Handle). frps collects every failing plugin as "[pluginName]: err", joined with '; '. Unlike rejection, this is a plugin invocation failure during proxy teardown.
Source
Thrown at pkg/plugin/server/manager.go:154
func (m *Manager) CloseProxy(content *CloseProxyContent) error {
if len(m.closeProxyPlugins) == 0 {
return nil
}
errs := make([]string, 0)
ctx, xl := newPluginRequestContext()
for _, p := range m.closeProxyPlugins {
_, _, err := p.Handle(ctx, OpCloseProxy, *content)
if err != nil {
xl.Warnf("send CloseProxy request to plugin [%s] error: %v", p.Name(), err)
errs = append(errs, fmt.Sprintf("[%s]: %v", p.Name(), err))
}
}
if len(errs) > 0 {
return fmt.Errorf("send CloseProxy request to plugin errors: %s", strings.Join(errs, "; "))
}
return nil
}
func (m *Manager) Ping(content *PingContent) (*PingContent, error) {
return handleMutableContent(m.pingPlugins, OpPing, content, pluginErrorLogWarn)
}
func (m *Manager) NewWorkConn(content *NewWorkConnContent) (*NewWorkConnContent, error) {
return handleMutableContent(m.newWorkConnPlugins, OpNewWorkConn, content, pluginErrorLogWarn)
}
func (m *Manager) NewUserConn(content *NewUserConnContent) (*NewUserConnContent, error) {
// Preserve the pre-refactor log level for NewUserConn plugin errors.
return handleMutableContent(m.newUserConnPlugins, OpNewUserConn, content, pluginErrorLogInfo)
}
View on GitHub (pinned to 6c8a8d0a97)
Solutions
- Identify the failing plugin from the [name]: err entries in the message
- Check whether the plugin process is alive and its endpoint reachable from frps
- Make the plugin return 200 withunchanged for CloseProxy if it does not track proxy state
- Since this occurs during teardown, assess whether the error has real impact; failing closes usually just leak plugin-side bookkeeping
Defensive patterns
Strategy: try-catch
Try / catch
if err := manager.CloseProxy(content); err != nil {
// teardown best-effort: log, don't fail the close path
log.Warnf("close proxy plugin errors (non-fatal): %v", err)
} Prevention
- Treat CloseProxy plugin errors as warnings; don't abort proxy teardown on them
- Keep plugin services highly available or make them tolerate unavailability during close
- Implement all ops in the plugin, returning unchange for ones you don't track
When it happens
Trigger: Manager.CloseProxy iterating m.closeProxyPlugins where at least one p.Handle returns err — plugin endpoint unreachable, timed out, or returned non-200 while frps was closing a proxy.
Common situations: Plugin service restarted or down when proxies close; plugin only partially implements operations and errors on CloseProxy; network blip between frps and the plugin.
Related errors
- send ${op} request to plugin error
- do http request error code: %d
- %s
- no route found
- router config conflict
AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15).
Data as JSON: /api/errors/245e1d94661fe336.
Report an issue: GitHub.