{"record":{"id":"a2b4857f8a4644e0","repo":"AlexxIT/go2rtc","slug":"av-login-2-failed-w","errorCode":null,"errorMessage":"av login 2 failed: %w","messagePattern":"av login 2 failed: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/tutk/dtls/conn_dtls.go","lineNumber":183,"sourceCode":"\tgo c.worker()\n\n\treturn c, nil\n}\n\nfunc (c *DTLSConn) AVClientStart(timeout time.Duration) error {\n\trandomID := tutk.GenSessionID()\n\tpkt1 := c.msgAVLogin(magicAVLogin1, 570, 0x0001, randomID)\n\tpkt2 := c.msgAVLogin(magicAVLogin2, 572, 0x0000, randomID)\n\tpkt2[20]++ // pkt2 has randomID incremented by 1\n\n\tif _, err := c.clientConn.Write(pkt1); err != nil {\n\t\treturn fmt.Errorf(\"av login 1 failed: %w\", err)\n\t}\n\n\ttime.Sleep(10 * time.Millisecond)\n\n\tif _, err := c.clientConn.Write(pkt2); err != nil {\n\t\treturn fmt.Errorf(\"av login 2 failed: %w\", err)\n\t}\n\n\t// Wait for response\n\ttimer := time.NewTimer(timeout)\n\tdefer timer.Stop()\n\tfor {\n\t\tselect {\n\t\tcase data, ok := <-c.rawCmd:\n\t\t\tif !ok {\n\t\t\t\treturn io.EOF\n\t\t\t}\n\t\t\tif len(data) >= 32 && binary.LittleEndian.Uint16(data) == magicAVLoginResp {\n\t\t\t\tc.hasTwoWayStreaming = data[31] == 1\n\n\t\t\t\tack := c.msgACK()\n\t\t\t\tc.clientConn.Write(ack)\n\n\t\t\t\t// Start ACK sender for continuous streaming","sourceCodeStart":165,"sourceCodeEnd":201,"githubUrl":"https://github.com/AlexxIT/go2rtc/blob/c245815e75e2a5fd60b4290f12bfc04e55a984d3/pkg/tutk/dtls/conn_dtls.go#L165-L201","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nif _, err := c.clientConn.Write(pkt2); err != nil {\n\treturn fmt.Errorf(\"av login 2 failed: %w\", err)\n}\n// after\nif _, err := c.clientConn.Write(pkt2); err != nil {\n\tif errors.Is(err, net.ErrClosed) || errors.Is(err, os.ErrDeadlineExceeded) {\n\t\tc.Close()\n\t\treturn fmt.Errorf(\"av login 2 failed, session dead: %w\", err)\n\t}\n\treturn fmt.Errorf(\"av login 2 failed: %w\", err)\n}","handlingStrategy":"retry","validationCode":"if conn == nil || conn.IsClosed() {\n\treturn fmt.Errorf(\"AV session not established\")\n}","typeGuard":null,"tryCatchPattern":"err := conn.AVClientStart(timeout)\nif err != nil {\n\tif errors.Is(err, os.ErrDeadlineExceeded) {\n\t\t// rebuild session then retry once\n\t}\n\treturn err\n}","preventionTips":["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"],"tags":["network","dtls","handshake","timeout"],"backgroundTag":"network-request-failed","analyzedSha":"c245815e75e2a5fd60b4290f12bfc04e55a984d3","analyzedAt":"2026-09-07T11:47:02.965Z","contentChangedAt":"2026-09-07T11:47:02.965Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}