{"record":{"id":"3033c567f39d97a5","repo":"slackhq/nebula","slug":"inetwork-getcategory-s","errorCode":null,"errorMessage":"INetwork.GetCategory: %s","messagePattern":"INetwork\\.GetCategory: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"overlay/network_category_windows.go","lineNumber":233,"sourceCode":"\tIsConnected                uintptr\n\tGetConnectivity            uintptr\n\tGetCategory                uintptr\n\tSetCategory                uintptr\n}\n\ntype iNetwork struct{ Vtbl *iNetworkVtbl }\n\nfunc (n *iNetwork) Release() {\n\tsyscall.SyscallN(n.Vtbl.Release, uintptr(unsafe.Pointer(n)))\n}\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.","sourceCodeStart":215,"sourceCodeEnd":251,"githubUrl":"https://github.com/slackhq/nebula/blob/dd8f660c0ac37903ec4080ca4d3c861ba9342ceb/overlay/network_category_windows.go#L215-L251","documentation":"This error wraps a failed HRESULT from INetwork::GetCategory, which reads the NLM_NETWORK_CATEGORY (public/private/domain) of a Windows network. It is the core query used to map the OS category onto Nebula's networkCategory during tun setup. A failing HRESULT means the COM call failed rather than the category being unknown.","triggerScenarios":"Calling GetCategory() on an iNetwork pointer obtained via GetNetwork() while classifying the tunnel adapter, when the COM vtbl call returns a failed HRESULT.","commonSituations":"Transient NLM service failure during tunnel startup; stale INetwork pointer after the network profile changed or was deleted; COM apartment/threading violations in service contexts.","solutions":["Retry the classification once with a freshly obtained INetwork pointer","Verify the Network List Service (netprofm) is running and healthy","Keep the COM object usage on the thread where COM was initialized","Parse the hresult in the message for the specific COM failure and degrade gracefully (leave category unset) when classification is best-effort"],"exampleFix":"// before\ncat, err := net.GetCategory()\nif err != nil { return err }\n// after\ncat, err := net.GetCategory()\nif err != nil {\n    l.WithError(err).Warn(\"unable to read network category; leaving category unset\")\n    return 0, false, nil\n}","handlingStrategy":"retry","validationCode":"// preflight service availability\nfunc nlmReady() bool {\n    state, err := svcQuery(\"netprofm\")\n    return err == nil && state == \"RUNNING\"\n}","typeGuard":"func isGetCategoryError(err error) bool {\n    return err != nil && strings.HasPrefix(err.Error(), \"INetwork.GetCategory:\")\n}","tryCatchPattern":"cat, err := net.GetCategory()\nif err != nil {\n    time.Sleep(250 * time.Millisecond)\n    if n2, rerr := refreshNetwork(); rerr == nil {\n        cat, err = n2.GetCategory()\n    }\n    if err != nil {\n        log.Warnf(\"category read failed, leaving unset: %v\", err)\n        return 0, false, nil\n    }\n}","preventionTips":["Use fresh INetwork pointers; stale ones fail transient calls","Keep the COM apartment consistent for the entire classification chain","Retry transient HRESULT failures once before giving up","Default to leaving the category unset instead of failing tunnel startup"],"tags":["windows","com","winapi","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"}