AlexxIT/go2rtc · error
onvif: wrong response
Error message
onvif: wrong response ${res.Status} What it means
Request in pkg/onvif/client.go performs the HTTP POST of the SOAP envelope to the resolved ONVIF service URL and, if the HTTP response status is anything other than 200 OK, returns errors.New("onvif: wrong response "+res.Status). The res.Status text includes the numeric code and reason phrase, so this is the ONVIF device rejecting the request at the HTTP transport layer before any SOAP body parsing happens.
Solutions
- Check the numeric code in the message: 401 means fix credentials — pass correct username:password in the device URL userinfo and re-dial
- Confirm the service URL scheme/port matches the camera (http vs https, port 80/8899/etc.) via GetCapabilities/GetServices
- Retry after a delay for 5xx — cameras commonly return 503 while rebooting or under load
- Capture the response body with a raw HTTP client/proxy to see whether the camera returned a SOAP fault with the status
- Update camera firmware if it returns 400/500 for spec-compliant requests
Example fix
// before
uri, err := cam.GetStreamUri(...) // "onvif: wrong response 401 Unauthorized"
// after
// ensure credentials are part of the dial URL
u, _ := url.Parse("onvif://admin:correctpass@192.168.1.64:80/onvif/device_service")
cam, err := onvif.Dial(ctx, u)
if err != nil { return err }
uri, err := cam.GetStreamUri(...) Defensive patterns
Strategy: retry
Validate before calling
if u.User == nil || u.User.Username() == "" {
return errors.New("onvif: device URL missing credentials")
} Type guard
func isHTTPStatusErr(err error, code string) bool {
return err != nil && strings.Contains(err.Error(), "onvif: wrong response "+code)
} Try / catch
var data []byte
for i := 0; i < 3; i++ {
data, err = cam.DeviceRequest(ctx, op)
if err == nil { break }
if strings.Contains(err.Error(), "401") {
return fmt.Errorf("onvif auth failed: check credentials in device URL")
}
if strings.Contains(err.Error(), "onvif: wrong response 5") {
time.Sleep(time.Duration(1<<i) * time.Second)
continue
}
return err
} Prevention
- Embed correct username:password in the ONVIF URL and rotate camera passwords centrally
- Match URL scheme and port to what the camera advertises via GetCapabilities
- Retry 5xx responses with exponential backoff — cameras return 503 during reboots
- Test calls against the camera with a raw HTTP client to see SOAP fault bodies behind non-200 statuses
When it happens
Trigger: Any ONVIF call (GetProfile, GetStreamUri, GetSnapshotUri, GetServiceCapabilities, DeviceRequest, etc.) against a camera that answers 401 Unauthorized (bad/missing credentials in the URL userinfo), 404 (wrong service path), 405, or 5xx (device overloaded/rebooting).
Common situations: Wrong username/password (or wrong digest-auth handling) in the ONVIF URL; camera firmware changing service paths; camera mid-reboot returning 503; calling an HTTPS URL on an HTTP-only port or vice versa; WS-Addressing/Action headers rejected by stricter firmwares returning 400/500.
Related errors
AI-assisted analysis of AlexxIT/go2rtc@c245815e75 (2026-09-07).
Data as JSON: /api/errors/8cef575b4f3b7ece.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/onvif/client.go:193
}
func (c *Client) Request(url, body string) ([]byte, error) {
if url == "" {
return nil, errors.New("onvif: unsupported service")
}
e := NewEnvelopeWithUser(c.url.User)
e.Append(body)
client := &http.Client{Timeout: time.Second * 5000}
res, err := client.Post(url, `application/soap+xml;charset=utf-8`, bytes.NewReader(e.Bytes()))
if err != nil {
return nil, err
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return nil, errors.New("onvif: wrong response " + res.Status)
}
return io.ReadAll(res.Body)
}
View on GitHub (pinned to c245815e75)