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

  1. Read the status text embedded in the error message and fix the underlying cause: 401/403 means fix credentials or pairing state.
  2. Verify the camera URL/path configuration matches what this driver expects for your camera model/firmware.
  3. If the camera is paired elsewhere, use Unpair or unpair via the camera web UI before dialing.
  4. Check camera firmware; update to a version that supports the control endpoint, or use the correct vendor driver.
  5. 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

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)