AlexxIT/go2rtc · warning

err.Error()

Error message

err.Error()

What it means

go2rtc's ONVIF device-service endpoint (/onvif/) reads the entire SOAP request body with io.ReadAll before deciding how to respond. If reading the body fails mid-transfer, the handler converts the raw error string to an HTTP 500 response. This means the ONVIF client's request never arrived intact, so no ONVIF processing could be attempted.

Solutions

  1. Check the go2rtc logs and the client for a simultaneous connection-abort/timeout error at the same timestamp
  2. Verify network stability (proxy, LB, docker networking) between the ONVIF client and go2rtc
  3. Increase the client's request timeout so slow body uploads are not aborted
  4. Retry the ONVIF request; transient disconnects are usually client-side

Example fix

// before (client side)
req, _ := http.NewRequest("POST", url, body) // no timeout control
// after (client side)
client := &http.Client{Timeout: 30 * time.Second}
client.Do(req)
Defensive patterns

Strategy: try-catch

Validate before calling

// client side: ensure the request completes and the body is fully written before abandoning
req, _ := http.NewRequest("POST", "http://server:1984/onvif/", bytes.NewReader(soapBody))
req.Header.Set("Content-Type", "application/soap+xml")

Try / catch

resp, err := client.Do(req)
if err != nil {
    // retry once on transport failure before surfacing
    resp, err = client.Do(req)
    if err != nil { return fmt.Errorf("onvif request failed: %w", err) }
}
if resp.StatusCode == http.StatusInternalServerError {
    // server failed reading our body: likely our connection dropped; retry
}

Prevention

When it happens

Trigger: A client POSTs a SOAP request to /onvif/... and the TCP connection breaks or the request is aborted while the server is still reading the body (client disconnect, timeout, corrupted chunked transfer).

Common situations: Clients with aggressive timeouts dropping the connection mid-request; network interruptions between an NVR (e.g. Home Assistant) and go2rtc; HTTP proxies or load balancers terminating long-running uploads; rare client bugs sending invalid chunked encoding.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


AI-assisted analysis of AlexxIT/go2rtc@c245815e75 (2026-09-07). Data as JSON: /api/errors/d59dad83f79d3fcb. Report an issue: GitHub.

Appendix: source

Thrown at internal/onvif/onvif.go:64

	// Append hash-based arguments to the retrieved URI
	if i := strings.IndexByte(rawURL, '#'); i > 0 {
		uri += rawURL[i:]
	}

	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,

View on GitHub (pinned to c245815e75)