cloudflare/cloudflared · warning
400 Bad Request
Error message
400 Bad Request
What it means
This is the fallback plain-text response written by writeHTTPErrorResponse in the management middleware when encoding the structured JSON error body fails. Because the HTTP status header (400) has already been written, the middleware can only emit a basic '400 Bad Request' text body. It signals a client sent a request the management API could not accept AND that the error payload itself could not be serialized.
Source
Thrown at management/middleware.go:63
// Middleware validation error HTTP response JSON for returning to the eyeball
type managementErrorResponse struct {
Success bool `json:"success,omitempty"`
Errors []managementError `json:"errors,omitempty"`
}
// writeErrorResponse will respond to the eyeball with basic HTTP JSON payloads with validation failure information
func writeHTTPErrorResponse(w http.ResponseWriter, errResp managementError) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusBadRequest)
err := json.NewEncoder(w).Encode(managementErrorResponse{
Success: false,
Errors: []managementError{errResp},
})
// we have already written the header, so write a basic error response if unable to encode the error
if err != nil {
// fallback to text message
http.Error(w, fmt.Sprintf(
"%d %s",
http.StatusBadRequest,
http.StatusText(http.StatusBadRequest),
), http.StatusBadRequest)
}
}
View on GitHub (pinned to 2253eeeb25)
Solutions
- Inspect the request body/parameters sent to the management API and correct them (valid JSON, required fields present)
- Set Content-Type: application/json and send a well-formed management protocol message
- Use an up-to-date cloudflared client so request/response schemas match the running daemon version
- Check cloudflared logs for the original error that triggered the 400 to identify the rejected field
Example fix
// before: malformed management request
{"unknown_field": true}
// after
{"type": "grpc-request", "body": {"request_type": "configuration", "version": {}}}
{"capabilities": [], "version": "2023.4.1"} Defensive patterns
Strategy: validation
Validate before calling
body, _ := json.Marshal(managementReq)
if !json.Valid(body) {
return errors.New("management request payload is not valid JSON")
}
req.Header.Set("Content-Type", "application/json") Try / catch
resp, err := http.Post(managementURL, "application/json", bytes.NewReader(body))
if err != nil {
return err
}
if resp.StatusCode == http.StatusBadRequest {
var mgmtResp struct{ Errors []struct{ Code int; Message string } `json:"errors"` }
json.NewDecoder(resp.Body).Decode(&mgmtResp)
return fmt.Errorf("management API rejected request: %+v", mgmtResp.Errors)
} Prevention
- Validate request JSON against the management protocol schema before sending
- Use a client matching the running cloudflared version
- Parse the structured JSON errors field when present rather than the text fallback
- Enable debug logging on the daemon to see why the 400 was raised
When it happens
Trigger: A client sends an invalid request to the cloudflared management API (bad JSON body or invalid query parameters); the handler writes a 400 header, and then json encoding of the managementError response fails, triggering the http.Error fallback with the literal '400 Bad Request' text.
Common situations: Programmatic clients POSTing malformed JSON to the management endpoint; missing required fields in management request payloads; tooling hitting the wrong endpoint shape; handcrafted curl requests with wrong content type.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
- failed to unmarshal quick Tunnel
- failed to decode HTTP response
- ErrBadRequest
- ErrAPINoSuccess
- Failed to fetch page. Server returned: %d
AI-assisted analysis of cloudflare/cloudflared@2253eeeb25 (2026-09-06).
Data as JSON: /api/errors/4c210bda6819ba8d.
Report an issue: GitHub.