AlexxIT/go2rtc · error
wrong response:
Error message
wrong response:
What it means
Dial (pkg/bubble/client.go:90) is establishing a session with a Bubble camera over its HTTP/TCP control channel. After sending the initial request it reads an HTTP-style response via tcp.ReadResponse; if the status code is not 200 OK it aborts and returns "wrong response: <status>". The appended res.Status text is the raw status line (e.g. "401 Unauthorized"), so this error means the camera rejected or failed the initial handshake request rather than returning a protocol error.
Solutions
- Read the status text embedded in the error message and fix the underlying cause: 401/403 means fix credentials or pairing state.
- Verify the camera URL/path configuration matches what this driver expects for your camera model/firmware.
- If the camera is paired elsewhere, use Unpair or unpair via the camera web UI before dialing.
- Check camera firmware; update to a version that supports the control endpoint, or use the correct vendor driver.
- Confirm you are connecting directly to the camera (no proxy/NAT rewriting the HTTP response).
Example fix
// before: credentials not set / wrong client, err := bubble.Dial(ctx, logger, "192.168.1.64:80", "", "") // after: supply correct camera credentials client, err := bubble.Dial(ctx, logger, "192.168.1.64:80", "admin", "camera-password")
Defensive patterns
Strategy: try-catch
Validate before calling
// preflight the camera's HTTP endpoint
resp, err := http.Get("http://" + addr + "/")
if err == nil && resp.StatusCode != http.StatusOK {
log.Printf("camera answers %s; check credentials/pairing", resp.Status)
} Try / catch
client, err := bubble.Dial(ctx, log, addr, user, pass)
if err != nil && strings.Contains(err.Error(), "wrong response:") {
return fmt.Errorf("camera rejected handshake (%w); check credentials and pairing", err)
} Prevention
- Store and verify camera credentials before dialing
- Unpair the camera from any previous NVR first
- Pin supported camera models/firmware for this driver
- Avoid proxies on the camera network path
When it happens
Trigger: Calling Dial, Unpair, TestTimeout, or TestMissedControl when the camera responds to the initial control request with a non-200 HTTP status (401 Unauthorized for bad credentials, 404/500 for wrong URL path or firmware behavior, 4xx/5xx of any kind).
Common situations: Wrong username/password configured for the camera; camera model or firmware that doesn't support the endpoint being hit; camera already paired to another NVR returning 403/409; pointing the client at a non-Bubble HTTP service that answers with a non-200 status; proxy or captive portal intercepting the connection.
Related errors
AI-assisted analysis of AlexxIT/go2rtc@c245815e75 (2026-09-07).
Data as JSON: /api/errors/f39e8e7101befaef.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/bubble/client.go:90
}
if err = c.conn.SetDeadline(time.Now().Add(Timeout)); err != nil {
return
}
req := &tcp.Request{Method: "GET", URL: &url.URL{Path: u.Path, RawQuery: u.RawQuery}, Proto: "HTTP/1.1"}
if err = req.Write(c.conn); err != nil {
return
}
c.r = bufio.NewReader(c.conn)
res, err := tcp.ReadResponse(c.r)
if err != nil {
return
}
if res.StatusCode != http.StatusOK {
return errors.New("wrong response: " + res.Status)
}
// 1. Read 1024 bytes with XML, some cameras returns exact 1024, but some - 923
xml := make([]byte, 1024)
if _, err = c.r.Read(xml); err != nil {
return
}
// 2. Write size uint32 + unknown 4b + user 20b + pass 20b
b := make([]byte, 48)
binary.BigEndian.PutUint32(b, 44)
if u.User != nil {
copy(b[8:], u.User.Username())
pass, _ := u.User.Password()
copy(b[28:], pass)
} else {
copy(b[8:], "admin")View on GitHub (pinned to c245815e75)