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
- Check the go2rtc logs and the client for a simultaneous connection-abort/timeout error at the same timestamp
- Verify network stability (proxy, LB, docker networking) between the ONVIF client and go2rtc
- Increase the client's request timeout so slow body uploads are not aborted
- 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
- Set generous client timeouts for ONVIF POSTs
- Keep ONVIF client and go2rtc on the same stable LAN segment
- Avoid proxies that idle-timeout long SOAP requests
- Monitor for repeated disconnect patterns in logs
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)