{"record":{"id":"759f2a180a4dec57","repo":"slackhq/nebula","slug":"inetwork-setcategory-s","errorCode":null,"errorMessage":"INetwork.SetCategory: %s","messagePattern":"INetwork\\.SetCategory: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"overlay/network_category_windows.go","lineNumber":243,"sourceCode":"}\n\nfunc (n *iNetwork) GetCategory() (networkCategory, error) {\n\tvar c networkCategory\n\tr1, _, _ := syscall.SyscallN(n.Vtbl.GetCategory,\n\t\tuintptr(unsafe.Pointer(n)), uintptr(unsafe.Pointer(&c)),\n\t)\n\tif hr := hresult(r1); hr.failed() {\n\t\treturn 0, fmt.Errorf(\"INetwork.GetCategory: %s\", hr)\n\t}\n\treturn c, nil\n}\n\nfunc (n *iNetwork) SetCategory(c networkCategory) error {\n\tr1, _, _ := syscall.SyscallN(n.Vtbl.SetCategory,\n\t\tuintptr(unsafe.Pointer(n)), uintptr(int32(c)),\n\t)\n\tif hr := hresult(r1); hr.failed() {\n\t\treturn fmt.Errorf(\"INetwork.SetCategory: %s\", hr)\n\t}\n\treturn nil\n}\n\n// coInit initializes COM for the current OS thread. The returned function must\n// be deferred to balance a successful init. RPC_E_CHANGED_MODE means COM is\n// already initialized in a different mode on this thread, which is still fine\n// for our calls but we must not Uninitialize in that case.\nfunc coInit() (func(), error) {\n\terr := windows.CoInitializeEx(0, windows.COINIT_MULTITHREADED)\n\tif err == nil {\n\t\treturn windows.CoUninitialize, nil\n\t}\n\tif e, ok := err.(syscall.Errno); ok {\n\t\tswitch uint32(e) {\n\t\tcase hrSFALSE:\n\t\t\treturn windows.CoUninitialize, nil\n\t\tcase hrRPCEChangedMode:","sourceCodeStart":225,"sourceCodeEnd":261,"githubUrl":"https://github.com/slackhq/nebula/blob/dd8f660c0ac37903ec4080ca4d3c861ba9342ceb/overlay/network_category_windows.go#L225-L261","documentation":"This error wraps a failed HRESULT from INetwork::SetCategory, which writes a new NLM_NETWORK_CATEGORY (public/private/domain) for a Windows network. Nebula uses it to persist the configured tun.network_category onto the underlying OS network profile. A failing HRESULT means Windows refused the update — commonly due to insufficient privileges or service issues.","triggerScenarios":"Calling SetCategory(c) during tun setup when applying the user's configured network_category, and the NLM COM vtbl call returns a failing HRESULT (e.g. E_ACCESSDENIED from a non-elevated process).","commonSituations":"Running Nebula as a non-admin service without rights to change network profiles; group policy locking network profile changes; NLM service stopped; stale INetwork pointer after profile changes.","solutions":["Run the process elevated (or as LocalSystem) so it has permission to change network profiles","Verify the Network List Service (netprofm) is running before startup","Check the hresult in the message: E_ACCESSDENIED → privileges; service errors → restart netprofm","Re-acquire the INetwork pointer via GetNetworkConnections/GetNetwork if the network profile changed before the write"],"exampleFix":"// before: ignoring why the write failed\nif err := net.SetCategory(cat); err != nil { return err }\n// after: distinguish privilege failures\nif err := net.SetCategory(cat); err != nil {\n    if strings.Contains(err.Error(), \"Access is denied\") {\n        return fmt.Errorf(\"setting network category requires elevation: %w\", err)\n    }\n    return err\n}","handlingStrategy":"try-catch","validationCode":"// check write permission context before attempting SetCategory\nfunc canSetCategory() error {\n    if !isAdminOrLocalSystem() {\n        return fmt.Errorf(\"changing network category requires elevation\")\n    }\n    return nil\n}","typeGuard":"func isSetCategoryError(err error) bool {\n    return err != nil && strings.HasPrefix(err.Error(), \"INetwork.SetCategory:\")\n}","tryCatchPattern":"err := net.SetCategory(cat)\nif err != nil {\n    log.Warnf(\"could not persist network category (running elevated?): %v\", err)\n    // continue startup; category persistence is secondary\n}","preventionTips":["Run the tunnel service elevated/LocalSystem when network_category is configured","Confirm the Network List Service is running before writing","Check the hresult for E_ACCESSDENIED and surface a clear privilege hint","Re-acquire the INetwork pointer if the profile changed before the write"],"tags":["windows","com","winapi","privileges","network-category"],"backgroundTag":"com-call-failed","analyzedSha":"dd8f660c0ac37903ec4080ca4d3c861ba9342ceb","analyzedAt":"2026-09-03T11:13:55.444Z","contentChangedAt":"2026-09-03T11:13:55.444Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}