AlexxIT/go2rtc · error
malformed request body
Error message
malformed request body
What it means
The ONVIF device-service handler parses the SOAP body with onvif.GetRequestAction to identify which ONVIF operation the client wants. If the body yields an empty action, go2rtc cannot map the request to any known operation and returns 400 "malformed request body". The library expects a well-formed ONVIF SOAP envelope with a recognizable action element.
Solutions
- Send a valid ONVIF SOAP envelope with the action element (e.g. an ONVIF Device/Media operation)
- Verify with curl -d @request.xml that the POST body is non-empty XML
- Enable go2rtc trace logging and compare the failing request with one from a known-good ONVIF client
- Use a standard ONVIF client library instead of hand-crafted SOAP
Example fix
// before curl -X POST http://server:1984/onvif/ # empty body // after curl -X POST http://server:1984/onvif/ -H 'Content-Type: application/soap+xml' --data @get_profiles.xml
Defensive patterns
Strategy: validation
Validate before calling
body, _ := io.ReadAll(respBody)
if len(bytes.TrimSpace(body)) == 0 || !bytes.Contains(body, []byte("<")) {
return errors.New("request body must be a non-empty SOAP XML envelope")
} Try / catch
resp, err := http.Post(url, "application/soap+xml", bytes.NewReader(soapBody))
if err != nil { return err }
if resp.StatusCode == http.StatusBadRequest {
b, _ := io.ReadAll(resp.Body)
if strings.Contains(string(b), "malformed request body") {
return fmt.Errorf("invalid SOAP envelope sent to ONVIF endpoint: %s", b)
}
} Prevention
- Always send Content-Type: application/soap+xml to /onvif/
- Validate SOAP envelopes against a known-good ONVIF template
- Never GET or POST empty bodies to the ONVIF endpoint
- Compare with a captured request from a working ONVIF client
When it happens
Trigger: POSTing to /onvif/ a body that is empty, not XML, lacks the SOAP action tag, or uses an encoding/namespaces the simple parser cannot read.
Common situations: Sending plain JSON or form data instead of SOAP; hitting the endpoint with a browser GET/health-check or curl without a body; using an ONVIF client that sends unusual namespaces; a reverse proxy stripping the body.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- onvif: wrong response
- Code must be in the range [0, 125]
- either email/password or refresh_token is required
- either email/password or refresh token is required
- empty username or password
AI-assisted analysis of AlexxIT/go2rtc@c245815e75 (2026-09-07).
Data as JSON: /api/errors/25c1910d70a7d781.
Report an issue: GitHub.
Appendix: source
Thrown at internal/onvif/onvif.go:70
log.Debug().Msgf("[onvif] new uri=%s", uri)
if err = streams.Validate(uri); err != nil {
return nil, err
}
return streams.GetProducer(uri)
}
func onvifDeviceService(w http.ResponseWriter, r *http.Request) {
b, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
operation := onvif.GetRequestAction(b)
if operation == "" {
http.Error(w, "malformed request body", http.StatusBadRequest)
return
}
log.Trace().Msgf("[onvif] server request %s %s:\n%s", r.Method, r.RequestURI, b)
switch operation {
case onvif.ServiceGetServiceCapabilities, // important for Hass
onvif.DeviceGetNetworkInterfaces, // important for Hass
onvif.DeviceGetSystemDateAndTime, // important for Hass
onvif.DeviceSetSystemDateAndTime, // return just OK
onvif.DeviceGetDiscoveryMode,
onvif.DeviceGetDNS,
onvif.DeviceGetHostname,
onvif.DeviceGetNetworkDefaultGateway,
onvif.DeviceGetNetworkProtocols,
onvif.DeviceGetNTP,
onvif.DeviceGetScopes,
onvif.MediaGetVideoEncoderConfiguration,View on GitHub (pinned to c245815e75)