fatedier/frp · error
do http request error code: %d
Error message
do http request error code: %d
What it means
A server-side HTTP plugin returned a non-200 status code for an frps operation request (Login/NewUser/NewProxy/CloseProxy/Ping...). frps posts JSON to the plugin's HTTPAddr; any response other than http.StatusOK is rejected with this error, carrying the numeric status.
Source
Thrown at pkg/plugin/server/http.go:107
}
v := url.Values{}
v.Set("version", r.Version)
v.Set("op", r.Op)
req, err := http.NewRequest("POST", p.url+"?"+v.Encode(), bytes.NewReader(buf))
if err != nil {
return err
}
req = req.WithContext(ctx)
req.Header.Set("X-Frp-Reqid", GetReqidFromContext(ctx))
req.Header.Set("Content-Type", "application/json")
resp, err := p.client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("do http request error code: %d", resp.StatusCode)
}
buf, err = io.ReadAll(resp.Body)
if err != nil {
return err
}
return json.Unmarshal(buf, res)
}
View on GitHub (pinned to 6c8a8d0a97)
Solutions
- Map the status code: 404/405 means the path or method in the plugin config is wrong; 401/403 means the plugin refused the request; 5xx means the plugin itself errored
- Check the plugin service's own logs at the timestamp of the frps error
- Ensure the plugin implements the frps HTTP plugin protocol: always answer 200 and use the Reject/RejectReason fields for denials
- Verify [[httpPlugins]].addr points to the exact route handling the operation
Example fix
// before (plugin handler)
func handler(w http.ResponseWriter, r *http.Request) {
if !allowed(r) {
w.WriteHeader(http.StatusForbidden) // frps turns this into 'error code: 403'
return
}
}
// after — always 200, express denial in content
ret := HandleResponse{Reject: true, RejectReason: "not allowed"}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(ret) Defensive patterns
Strategy: try-catch
Validate before calling
// Health-check the plugin endpoint at frps startup
resp, err := http.Get(pluginAddr + "/healthz")
if err != nil || resp.StatusCode != 200 {
return errors.New("http plugin not ready")
} Try / catch
if err := manager.Login(content); err != nil {
if strings.Contains(err.Error(), "error code") {
// plugin answered with non-200: log status and consult plugin logs
log.Errorf("http plugin rejected op with status: %v", err)
}
} Prevention
- Implement frp plugin protocol correctly: always 200, denials via reject/reject_reason
- Add readiness checks for the plugin service before frps routes ops to it
- Return actionable bodies from non-200 responses so debugging is possible
When it happens
Trigger: frps configured with [[httpPlugins]], and the plugin endpoint returns 4xx/5xx — auth denial implemented as 403, plugin bug returning 500, wrong endpoint path returning 404, or a reverse proxy in front returning 502.
Common situations: Plugin deliberately rejects with non-200 instead of the expected 200+Reject pattern; plugin route not matching addr.path; plugin process down behind a gateway that answers 502/503; plugin framework returning 405 for a POST/GET method mismatch.
Related errors
- send ${op} request to plugin error
- no route found
- %s
- send CloseProxy request to plugin errors: %s
- router config conflict
AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15).
Data as JSON: /api/errors/7e6431b6cd8984de.
Report an issue: GitHub.