slackhq/nebula · error

unknown tun.network_category %q (expected public, private, d

Error message

unknown tun.network_category %q (expected public, private, domain, or unset)

What it means

parseNetworkCategory returns this error when the tun.network_category config value is a non-empty string that is not one of the accepted values: public, private, domain, or domainauthenticated (case-insensitive per the switch). The empty/unset string is treated as 'not set' and returns ok=false without error, so this error only fires for explicitly wrong values.

Source

Thrown at overlay/network_category_windows.go:53

		return "domain"
	}
	return fmt.Sprintf("unknown(%d)", c)
}

// parseNetworkCategory accepts the user-supplied tun.network_category. A
// second return of false means "leave the category alone".
func parseNetworkCategory(s string) (networkCategory, bool, error) {
	switch strings.ToLower(strings.TrimSpace(s)) {
	case "", "unset":
		return 0, false, nil
	case "public":
		return networkCategoryPublic, true, nil
	case "private":
		return networkCategoryPrivate, true, nil
	case "domain", "domainauthenticated":
		return networkCategoryDomainAuthenticated, true, nil
	}
	return 0, false, fmt.Errorf("unknown tun.network_category %q (expected public, private, domain, or unset)", s)
}

// CLSID_NetworkListManager {DCB00C01-570F-4A9B-8D69-199FDBA5723B}
var clsidNetworkListManager = windows.GUID{
	Data1: 0xDCB00C01, Data2: 0x570F, Data3: 0x4A9B,
	Data4: [8]byte{0x8D, 0x69, 0x19, 0x9F, 0xDB, 0xA5, 0x72, 0x3B},
}

// IID_INetworkListManager {DCB00000-570F-4A9B-8D69-199FDBA5723B}
var iidINetworkListManager = windows.GUID{
	Data1: 0xDCB00000, Data2: 0x570F, Data3: 0x4A9B,
	Data4: [8]byte{0x8D, 0x69, 0x19, 0x9F, 0xDB, 0xA5, 0x72, 0x3B},
}

// x/sys/windows doesn't expose CoCreateInstance, so we bind it ourselves.
var procCoCreateInstance = windows.NewLazySystemDLL("ole32.dll").NewProc("CoCreateInstance")

const clsCtxAll = windows.CLSCTX_INPROC_SERVER | windows.CLSCTX_INPROC_HANDLER |

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Set tun.network_category to exactly one of: public, private, domain, domainauthenticated — or remove the key entirely to leave it unset
  2. Trim whitespace and quotes around the value in the config file
  3. Check for YAML type coercion (e.g. an unquoted value being altered); quote the string
  4. Update the config template/docs on the machine to the current accepted keywords

Example fix

// before (config)
tun:
  network_category: Domian
// after
tun:
  network_category: domain
Defensive patterns

Strategy: validation

Validate before calling

var validCategories = map[string]bool{
    "public": true, "private": true,
    "domain": true, "domainauthenticated": true,
}
func validateCategory(s string) error {
    s = strings.ToLower(strings.TrimSpace(s))
    if s == "" || validCategories[s] {
        return nil
    }
    return fmt.Errorf("tun.network_category %q invalid", s)
}

Try / catch

cat, ok, err := parseNetworkCategory(cfg.Tun.NetworkCategory)
if err != nil {
    return fmt.Errorf("fix tun.network_category in config (%v)", err)
}

Prevention

When it happens

Trigger: Starting a Nebula tunnel on Windows with a tun.network_category setting containing a typo or unsupported value such as 'Public ', 'domian', 'DomainAuth', or a localized network profile name.

Common situations: Copy-pasting the Windows network profile name (e.g. 'Network 2') instead of the category keyword; case/spacing mistakes; following outdated documentation that used a different keyword; editing YAML with an unquoted value that got mangled.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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