slackhq/nebula · error

system socket

Error message

system socket: %v

What it means

newTun on macOS creates a utun control socket via unix.Socket(AF_SYSTEM, SOCK_DGRAM, AF_SYS_CONTROL). If that syscall fails, the raw errno is wrapped in this error. It indicates the kernel refused to open the special system-domain datagram socket used to talk to the utun kernel control interface.

Solutions

  1. Run nebula unsandboxed (outside App Sandbox) or grant the process the network extension entitlement that allows AF_SYSTEM socket creation.
  2. Check MDM/security profiles that block AF_SYSTEM sockets for the user.
  3. Ensure macOS kernel integrity protections allow third-party utun devices (up to 256 utun interfaces).
  4. Retry after rebooting if the kernel socket table is exhausted.
Defensive patterns

Strategy: try-catch

Try / catch

if err := run(); err != nil && strings.Contains(err.Error(), "system socket:") {
    // check sandbox/entitlements; prompt user to run outside App Sandbox
    log.Fatalf("cannot open utun control socket: %v", err)
}

Prevention

When it happens

Trigger: unix.Socket(AF_SYSTEM, SOCK_DGRAM, AF_SYS_CONTROL) returns an error at startup of newTun on Darwin — e.g. sandboxed/seatbelt profiles denying AF_SYSTEM sockets, heavily restricted CI macOS runners, or syscall emulation layers.

Common situations: Running nebula inside a macOS app sandbox without the com.apple.network.extension entitlements; running under jail/enterprise MDM restrictions; trying to create a second utun after resource limits.

Related errors


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

Appendix: source

Thrown at overlay/tun_darwin.go:94

	Lifetime   addrLifetime
}

func newTun(c *config.C, l *slog.Logger, vpnNetworks []netip.Prefix, _ bool) (*tun, error) {
	name := c.GetString("tun.dev", "")
	ifIndex := -1
	if name != "" && name != "utun" {
		_, err := fmt.Sscanf(name, "utun%d", &ifIndex)
		if err != nil || ifIndex < 0 {
			// NOTE: we don't make this error so we don't break existing
			// configs that set a name before it was used.
			l.Warn("interface name must be utun[0-9]+ on Darwin, ignoring")
			ifIndex = -1
		}
	}

	fd, err := unix.Socket(unix.AF_SYSTEM, unix.SOCK_DGRAM, unix.AF_SYS_CONTROL)
	if err != nil {
		return nil, fmt.Errorf("system socket: %v", err)
	}

	var ctlInfo = &unix.CtlInfo{}
	copy(ctlInfo.Name[:], utunControlName)

	err = unix.IoctlCtlInfo(fd, ctlInfo)
	if err != nil {
		return nil, fmt.Errorf("CTLIOCGINFO: %v", err)
	}

	err = unix.Connect(fd, &unix.SockaddrCtl{
		ID:   ctlInfo.Id,
		Unit: uint32(ifIndex) + 1,
	})
	if err != nil {
		return nil, fmt.Errorf("SYS_CONNECT: %v", err)
	}

View on GitHub (pinned to dd8f660c0a)