slackhq/nebula · error

only tcp is supported

Error message

only tcp is supported

What it means

Service.Listen exposes a net.Listener over the nebula tunnel, but the underlying implementation only supports TCP. Passing any network other than "tcp" or "tcp4" returns this error immediately. UDP/unix/other network types are not implemented.

Source

Thrown at service/service.go:212

			Port: uint16(addr.Port),
		}
		num := getProtocolNumber(addr.AddrPort().Addr())
		return gonet.DialContextTCP(ctx, s.ipstack, fullAddr, num)
	default:
		return nil, fmt.Errorf("unknown network type: %s", network)
	}
}

// Dial dials the provided address
func (s *Service) Dial(network, address string) (net.Conn, error) {
	return s.DialContext(context.Background(), network, address)
}

// Listen listens on the provided address. Currently only TCP with wildcard
// addresses are supported.
func (s *Service) Listen(network, address string) (net.Listener, error) {
	if network != "tcp" && network != "tcp4" {
		return nil, errors.New("only tcp is supported")
	}
	addr, err := net.ResolveTCPAddr(network, address)
	if err != nil {
		return nil, err
	}
	if addr.IP != nil && !bytes.Equal(addr.IP, []byte{0, 0, 0, 0}) {
		return nil, fmt.Errorf("only wildcard address supported, got %q %v", address, addr.IP)
	}
	if addr.Port == 0 {
		return nil, errors.New("specific port required, got 0")
	}
	if addr.Port < 0 || addr.Port >= math.MaxUint16 {
		return nil, fmt.Errorf("invalid port %d", addr.Port)
	}
	port := uint16(addr.Port)

	l := &tcpListener{
		port:   port,

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Change the network argument to "tcp" or "tcp4".
  2. Listen for UDP traffic via the tunnel with a different API — Service.Listen does not support datagram sockets.
  3. Normalize tcp6 requests to tcp4 since only wildcard IPv4 addresses are supported.

Example fix

// before
ln, err := s.Listen("udp", "127.0.0.1:8080")
// after
ln, err := s.Listen("tcp", "0.0.0.0:8080")
Defensive patterns

Strategy: validation

Validate before calling

if network != "tcp" && network != "tcp4" {
    return fmt.Errorf("Service.Listen supports only tcp/tcp4, got %q", network)
}

Try / catch

ln, err := s.Listen(network, address)
if err != nil {
    if err.Error() == "only tcp is supported" {
        return fmt.Errorf("use network \"tcp\" or \"tcp4\" with Service.Listen")
    }
    return err
}

Prevention

When it happens

Trigger: Calling s.Listen(network, address) with network values like "udp", "udp4", "unix", "tcp6" (note tcp6 is rejected; only tcp and tcp4 pass).

Common situations: Porting code that used net.Listen with "udp"; assuming tcp6 works since the address may be IPv4-mapped; generic proxy code parameterizing the network string.

Related errors


AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03). Data as JSON: /api/errors/4816f0303e65aa66. Report an issue: GitHub.