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

  1. Send a valid ONVIF SOAP envelope with the action element (e.g. an ONVIF Device/Media operation)
  2. Verify with curl -d @request.xml that the POST body is non-empty XML
  3. Enable go2rtc trace logging and compare the failing request with one from a known-good ONVIF client
  4. 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

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.

Related errors


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)