slackhq/nebula · error

could not create netstack NIC: %v

Error message

could not create netstack NIC: %v

What it means

service.New creates a channel-backed NIC in the gVisor netstack via CreateNIC(nicID, linkEP); a non-nil tcpip error aborts startup with this message. Without the NIC there is no link endpoint to route tunneled packets through.

Source

Thrown at service/service.go:84

	eg, ctx := errgroup.WithContext(ctx)
	s := Service{
		eg:      eg,
		control: control,
	}
	s.mu.listeners = map[uint16]*tcpListener{}

	s.ipstack = stack.New(stack.Options{
		NetworkProtocols:   []stack.NetworkProtocolFactory{ipv4.NewProtocol, ipv6.NewProtocol},
		TransportProtocols: []stack.TransportProtocolFactory{tcp.NewProtocol, udp.NewProtocol, icmp.NewProtocol4, icmp.NewProtocol6},
	})
	sackEnabledOpt := tcpip.TCPSACKEnabled(true) // TCP SACK is disabled by default
	tcpipErr := s.ipstack.SetTransportProtocolOption(tcp.ProtocolNumber, &sackEnabledOpt)
	if tcpipErr != nil {
		return nil, fmt.Errorf("could not enable TCP SACK: %v", tcpipErr)
	}
	linkEP := channel.New( /*size*/ 512 /*mtu*/, 1280, "")
	if tcpipProblem := s.ipstack.CreateNIC(nicID, linkEP); tcpipProblem != nil {
		return nil, fmt.Errorf("could not create netstack NIC: %v", tcpipProblem)
	}
	ipv4Subnet, _ := tcpip.NewSubnet(tcpip.AddrFrom4([4]byte{0x00, 0x00, 0x00, 0x00}), tcpip.MaskFrom(strings.Repeat("\x00", 4)))
	s.ipstack.SetRouteTable([]tcpip.Route{
		{
			Destination: ipv4Subnet,
			NIC:         nicID,
		},
	})

	ipNet := device.Networks()
	pa := tcpip.ProtocolAddress{
		AddressWithPrefix: tcpip.AddrFromSlice(ipNet[0].Addr().AsSlice()).WithPrefix(),
		Protocol:          ipv4.ProtocolNumber,
	}
	if err := s.ipstack.AddProtocolAddress(nicID, pa, stack.AddressProperties{
		PEB:        stack.CanBePrimaryEndpoint, // zero value default
		ConfigType: stack.AddressConfigStatic,  // zero value default
	}); err != nil {

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Ensure service.New creates its own fresh ipstack and uses the constant nicID only once
  2. If reusing a stack, pick a unique nicID or call NIC removal/Disable first
  3. Pin/upgrade the gVisor dependency to match the CreateNIC API this code expects
  4. Log the wrapped tcpipProblem to identify the exact error (e.g. ErrDuplicateNIC)

Example fix

// before
s.ipstack.CreateNIC(nicID, linkEP) // nicID already registered on this stack
// after
s.ipstack.RemoveNIC(nicID) // or use a fresh stack per service.New
s.ipstack.CreateNIC(nicID, linkEP)
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure one NIC per stack:
// create a fresh ipstack in service.New; do not share across instances

Try / catch

svc, err := service.New(...)
if err != nil {
    if strings.Contains(err.Error(), "netstack NIC") {
        log.Fatalf("NIC creation failed (duplicate nicID or gVisor API change): %v", err)
    }
    return err
}

Prevention

When it happens

Trigger: service.New is called and CreateNIC fails — typically duplicate nicID registration on the same stack, or a gVisor version where channel.New/endpoint registration semantics changed.

Common situations: Calling New twice on the same shared ipstack with the same nicID; custom netstack assembly code reusing nicID; gVisor API mismatch after dependency upgrade.

Related errors


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