AlexxIT/go2rtc · error
av login 2 failed
Error message
av login 2 failed: %w
What it means
AVClientStart wraps a failure of the second DTLS write of the AV login handshake on the client side. The library sends two login packets to the camera; if the second Write fails, the underlying DTLS/TUTK transport error is wrapped with %w so the root cause (timeout, closed channel, IOTC error) is preserved. It indicates the AV login exchange could not complete.
Solutions
- Inspect the wrapped cause (%w / errors.Unwrap) to see if it is a timeout vs closed connection
- Retry AVClientStart with a fresh DialDTLS session — the old DTLS conn is likely dead
- Verify the camera is reachable and the connection is stable (check for packet loss)
- Check that AV login packet construction (pkt2) matches the camera firmware expectations
Example fix
// before
if _, err := c.clientConn.Write(pkt2); err != nil {
return fmt.Errorf("av login 2 failed: %w", err)
}
// after
if _, err := c.clientConn.Write(pkt2); err != nil {
if errors.Is(err, net.ErrClosed) || errors.Is(err, os.ErrDeadlineExceeded) {
c.Close()
return fmt.Errorf("av login 2 failed, session dead: %w", err)
}
return fmt.Errorf("av login 2 failed: %w", err)
} Defensive patterns
Strategy: retry
Validate before calling
if conn == nil || conn.IsClosed() {
return fmt.Errorf("AV session not established")
} Try / catch
err := conn.AVClientStart(timeout)
if err != nil {
if errors.Is(err, os.ErrDeadlineExceeded) {
// rebuild session then retry once
}
return err
} Prevention
- Always rebuild the whole DTLS session after a login write failure — the conn is not reusable
- Check camera connectivity before starting AV sessions
- Unwrap and classify errors to decide retry vs re-dial
- Keep sessions short-lived on unstable WAN links
When it happens
Trigger: Calling AVClientStart (via doAVLogin) when the underlying channel write of the second login packet fails — DTLS session closed, camera dropped the connection between packet 1 and 2, or the TUTK channel errored.
Common situations: Camera rebooted or went offline mid-handshake; network drop over WAN; DTLS handshake succeeded but the camera closed the data channel because credentials/session were rejected; firewall dropping UDP after initial packets.
Related errors
- dtls: server handshake failed
- dtls: client handshake failed
- wrong response:
- dvrip: can't probe medias
- request failed after
AI-assisted analysis of AlexxIT/go2rtc@c245815e75 (2026-09-07).
Data as JSON: /api/errors/a2b4857f8a4644e0.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/tutk/dtls/conn_dtls.go:183
go c.worker()
return c, nil
}
func (c *DTLSConn) AVClientStart(timeout time.Duration) error {
randomID := tutk.GenSessionID()
pkt1 := c.msgAVLogin(magicAVLogin1, 570, 0x0001, randomID)
pkt2 := c.msgAVLogin(magicAVLogin2, 572, 0x0000, randomID)
pkt2[20]++ // pkt2 has randomID incremented by 1
if _, err := c.clientConn.Write(pkt1); err != nil {
return fmt.Errorf("av login 1 failed: %w", err)
}
time.Sleep(10 * time.Millisecond)
if _, err := c.clientConn.Write(pkt2); err != nil {
return fmt.Errorf("av login 2 failed: %w", err)
}
// Wait for response
timer := time.NewTimer(timeout)
defer timer.Stop()
for {
select {
case data, ok := <-c.rawCmd:
if !ok {
return io.EOF
}
if len(data) >= 32 && binary.LittleEndian.Uint16(data) == magicAVLoginResp {
c.hasTwoWayStreaming = data[31] == 1
ack := c.msgACK()
c.clientConn.Write(ack)
// Start ACK sender for continuous streamingView on GitHub (pinned to c245815e75)