m1k1o/neko · error · ErrWebRTCDataChannelNotFound

webrtc data channel not found

Error message

webrtc data channel not found

What it means

ErrWebRTCDataChannelNotFound is a sentinel error in the neko types package indicating that a WebRTC peer lookup for its data channel failed — the expected data channel (e.g. for cursor/control messages) has not been created or has not been opened yet. Code returns it when it tries to use a peer's data channel that is nil or absent.

Source

Thrown at server/pkg/types/webrtc.go:10

package types

import (
	"errors"

	"github.com/pion/webrtc/v4"
)

var (
	ErrWebRTCDataChannelNotFound = errors.New("webrtc data channel not found")
	ErrWebRTCConnectionNotFound  = errors.New("webrtc connection not found")
	ErrWebRTCStreamNotFound      = errors.New("webrtc stream not found")
)

type ICEServer struct {
	URLs       []string `mapstructure:"urls"       json:"urls"`
	Username   string   `mapstructure:"username"   json:"username,omitempty"`
	Credential string   `mapstructure:"credential" json:"credential,omitempty"`
}

type PeerVideo struct {
	Disabled bool   `json:"disabled"`
	ID       string `json:"id"`
	Video    string `json:"video"` // TODO: Remove this, used for compatibility with old clients.
	Auto     bool   `json:"auto"`
}

type PeerVideoRequest struct {

View on GitHub (pinned to b0f01cedea)

Solutions

  1. Ensure the WebRTC handshake (offer/answer, ICE) completed and the data channel is 'open' before sending messages.
  2. Check the client logs/browser console for ICE connection failures and fix STUN/TURN (ICEServers) configuration.
  3. Retry the send after the peer signals its data channel opened.
  4. Destroy and recreate the peer if the channel is permanently closed.
  5. Verify client and server neko versions are compatible (pion webrtc v4 negotiation).

Example fix

// before
err := peer.SendCursorPosition(x, y) // ErrWebRTCDataChannelNotFound if channel not open
// after
if peer.DataChannel() == nil || peer.DataChannel().ReadyState() != webrtc.DataChannelStateOpen {
    return nil // or queue the message until the channel opens
}
err := peer.SendCursorPosition(x, y)
Defensive patterns

Strategy: try-catch

Validate before calling

// only send after the data channel is open
if ch := peer.DataChannel(); ch == nil || ch.ReadyState() != webrtc.DataChannelStateOpen {
    return errors.New("data channel not open yet")
}

Type guard

func DataChannelReady(p types.WebRTCPeer) bool {
    ch := p.DataChannel()
    return ch != nil && ch.ReadyState() == webrtc.DataChannelStateOpen
}

Try / catch

if err := peer.SendCursorPosition(x, y); err != nil {
    if errors.Is(err, types.ErrWebRTCDataChannelNotFound) {
        // queue and resend once the channel opens
        return
    }
    return err
}

Prevention

When it happens

Trigger: Sending cursor position/cursor image over a peer whose data channel was never negotiated or not yet open; using a WebRTCPeer before the signaling/ICE handshake completes; after the data channel was closed by either side.

Common situations: Clients calling control APIs before the WebRTC connection finishes opening; ICE connection failures leaving the channel unestablished; browsers blocking WebRTC data channels (extensions, strict networks); peers destroyed mid-use.

Related errors


AI-assisted analysis of m1k1o/neko@b0f01cedea (2026-09-01). Data as JSON: /api/errors/9404ff53358a2c22. Report an issue: GitHub.