AlexxIT/go2rtc · error

multitrans: no session

Error message

multitrans: no session

What it means

After a successful (200) digest-auth response, the multitrans handshake expects an HTTP 'Session' header carrying the session ID. If the header is missing the client cannot open the talk channel, so it fails with this error. It indicates a device that authenticated but did not return the session token the protocol requires.

Solutions

  1. Update the device firmware to a version that returns the Session header on successful auth.
  2. Bypass proxies/load balancers that may strip non-standard headers like Session.
  3. Capture the handshake with a packet sniffer to confirm whether the header is present on the wire.
  4. Retry Dial; some devices intermittently omit the header under load.

Example fix

// before
res, _ := http.Get(proxyURL + "/device/talk") // proxy may strip Session

// after
res, _ := http.Get("http://" + deviceHost + "/device/talk") // talk directly to device
Defensive patterns

Strategy: fallback

Try / catch

if err := client.Dial(ctx); err != nil {
    if strings.Contains(err.Error(), "no session") {
        // device firmware issue; fall back to RTSP/snapshot API instead of talk
        return useRTSPFallback(ctx, device)
    }
    return err
}

Prevention

When it happens

Trigger: Calling Dial; handshake receives 200 OK but res.Header.Get("Session") is empty, then openTalkChannel is skipped and the error is returned.

Common situations: Firmware that omits the Session header or renames it; an intermediate proxy stripping custom headers; device at an unsupported firmware version.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at pkg/multitrans/client.go:158

		uri, authHeader, uid)

	if _, err = c.conn.Write([]byte(data)); err != nil {
		return err
	}

	res, err = tcp.ReadResponse(c.rd)
	if err != nil {
		return err
	}

	if res.StatusCode != http.StatusOK {
		return errors.New("multitrans: auth failed: " + res.Status)
	}

	// Session: 7116520596809429228
	session := res.Header.Get("Session")
	if session == "" {
		return errors.New("multitrans: no session")
	}

	return c.openTalkChannel(uri, session)
}

func (c *Client) openTalkChannel(uri, session string) error {
	payload := `{"type":"request","seq":0,"params":{"method":"get","talk":{"mode":"full_duplex"}}}`

	data := fmt.Sprintf("MULTITRANS %s RTSP/1.0\r\nCSeq: 2\r\nSession: %s\r\nContent-Type: application/json\r\nContent-Length: %d\r\n\r\n%s",
		uri, session, len(payload), payload)

	if _, err := c.conn.Write([]byte(data)); err != nil {
		return err
	}

	res, err := tcp.ReadResponse(c.rd)
	if err != nil {
		return err

View on GitHub (pinned to c245815e75)