{"record":{"id":"2c8dbdfb717c6c1f","repo":"AlexxIT/go2rtc","slug":"s-can-t-send-command-d","errorCode":null,"errorMessage":"%s: can't send command %d","messagePattern":"(.+?): can't send command (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/tutk/conn.go","lineNumber":143,"sourceCode":"\n\tc.cmdAck = func() {\n\t\trepeat.Store(0)\n\t\ttimeout.Reset(1)\n\t}\n\n\tbuf := c.session.SendIOCtrl(ctrlType, ctrlData)\n\n\tfor {\n\t\tif err := c.session.SessionWrite(0, buf); err != nil {\n\t\t\treturn err\n\t\t}\n\t\t<-timeout.C\n\t\tr := repeat.Add(-1)\n\t\tif r < 0 {\n\t\t\treturn nil\n\t\t}\n\t\tif r == 0 {\n\t\t\treturn fmt.Errorf(\"%s: can't send command %d\", \"tutk\", ctrlType)\n\t\t}\n\t}\n}\n\nfunc (c *Conn) ReadPacket() (hdr, payload []byte, err error) {\n\treturn c.session.RecvFrameData()\n}\n\nfunc (c *Conn) WritePacket(hdr, payload []byte) error {\n\tbuf := c.session.SendFrameData(hdr, payload)\n\treturn c.session.SessionWrite(1, buf)\n}\n\nfunc (c *Conn) Error() error {\n\tif c.err != nil {\n\t\treturn c.err\n\t}\n\treturn io.EOF","sourceCodeStart":125,"sourceCodeEnd":161,"githubUrl":"https://github.com/AlexxIT/go2rtc/blob/c245815e75e2a5fd60b4290f12bfc04e55a984d3/pkg/tutk/conn.go#L125-L161","documentation":"WriteCommand retries sending a TUTK control command a fixed number of times against a timeout; each failed attempt decrements a repeat counter. When the counter reaches zero the send still has not succeeded and this error is returned, meaning the command (identified by ctrlType) could not be delivered to the device.","triggerScenarios":"Calling WriteCommand (directly or via xiaofangLogin/login) when the underlying TUTK session cannot accept the frame within the retry budget — e.g. channel not established, device unreachable, or per-attempt timeout expiring repeatedly.","commonSituations":"Camera offline or on a flaky Wi-Fi link; P2P session not yet fully established when login commands are issued; firewall/NAT blocking the TUTK relay; too-short retry/timeout configuration for slow networks.","solutions":["Verify the device is reachable and the TUTK session (from Dial) established before sending commands.","Increase the repeat count/timeout used by WriteCommand to tolerate slow links.","Check NAT/firewall/relay configuration for the TUTK channel and retry Dial if the session went stale.","Log ctrlType and inspect the device side to confirm it is awake and accepting commands."],"exampleFix":"// before\nresp, err := conn.WriteCommand(ctrlType)\n// after\nif err := conn.Ping(); err != nil {\n\tconn, err = tutk.Dial(uid)\n\tif err != nil { log.Fatal(err) }\n}\nresp, err := conn.WriteCommand(ctrlType)","handlingStrategy":"retry","validationCode":"// Check session liveness before sending commands\nif conn == nil || conn.Closed() || !conn.SessionEstablished() {\n\tconn, err = tutk.Dial(uid)\n\tif err != nil { return err }\n}","typeGuard":null,"tryCatchPattern":"var resp []byte\nerr := retry.Do(3, time.Second, func() error {\n\tvar e error\n\tresp, e = conn.WriteCommand(ctrlType)\n\treturn e\n})\nif err != nil {\n\tconn, err = redial(uid) // re-establish before giving up\n}","preventionTips":["Verify device reachability before sending control commands","Increase retry/timeout budget for slow or flaky networks","Re-dial stale sessions instead of reusing them after timeouts","Monitor NAT/relay health for P2P connectivity issues"],"tags":["tutk","network","timeout","device"],"backgroundTag":"request-timeout","analyzedSha":"c245815e75e2a5fd60b4290f12bfc04e55a984d3","analyzedAt":"2026-09-07T11:47:02.965Z","contentChangedAt":"2026-09-07T11:47:02.965Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}