AlexxIT/go2rtc · error

: can't send command

Error message

%s: can't send command %d

What it means

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.

Solutions

  1. Verify the device is reachable and the TUTK session (from Dial) established before sending commands.
  2. Increase the repeat count/timeout used by WriteCommand to tolerate slow links.
  3. Check NAT/firewall/relay configuration for the TUTK channel and retry Dial if the session went stale.
  4. Log ctrlType and inspect the device side to confirm it is awake and accepting commands.

Example fix

// before
resp, err := conn.WriteCommand(ctrlType)
// after
if err := conn.Ping(); err != nil {
	conn, err = tutk.Dial(uid)
	if err != nil { log.Fatal(err) }
}
resp, err := conn.WriteCommand(ctrlType)
Defensive patterns

Strategy: retry

Validate before calling

// Check session liveness before sending commands
if conn == nil || conn.Closed() || !conn.SessionEstablished() {
	conn, err = tutk.Dial(uid)
	if err != nil { return err }
}

Try / catch

var resp []byte
err := retry.Do(3, time.Second, func() error {
	var e error
	resp, e = conn.WriteCommand(ctrlType)
	return e
})
if err != nil {
	conn, err = redial(uid) // re-establish before giving up
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


AI-assisted analysis of AlexxIT/go2rtc@c245815e75 (2026-09-07). Data as JSON: /api/errors/2c8dbdfb717c6c1f. Report an issue: GitHub.

Appendix: source

Thrown at pkg/tutk/conn.go:143

	c.cmdAck = func() {
		repeat.Store(0)
		timeout.Reset(1)
	}

	buf := c.session.SendIOCtrl(ctrlType, ctrlData)

	for {
		if err := c.session.SessionWrite(0, buf); err != nil {
			return err
		}
		<-timeout.C
		r := repeat.Add(-1)
		if r < 0 {
			return nil
		}
		if r == 0 {
			return fmt.Errorf("%s: can't send command %d", "tutk", ctrlType)
		}
	}
}

func (c *Conn) ReadPacket() (hdr, payload []byte, err error) {
	return c.session.RecvFrameData()
}

func (c *Conn) WritePacket(hdr, payload []byte) error {
	buf := c.session.SendFrameData(hdr, payload)
	return c.session.SessionWrite(1, buf)
}

func (c *Conn) Error() error {
	if c.err != nil {
		return c.err
	}
	return io.EOF

View on GitHub (pinned to c245815e75)