{"record":{"id":"c1b6eeec8a510497","repo":"hashicorp/nomad","slug":"topology-no-node-distance","errorCode":null,"errorMessage":"topology: no node distance","messagePattern":"topology: no node distance","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/lib/numalib/topology.go","lineNumber":160,"sourceCode":"func (st *Topology) NodeDistance(node hw.NodeID, core Core) Cost {\n\t// todo(shoenig) we should memoize these values - they never change but\n\t// they get used a lot in numa scheduling\n\n\t// fast path, core is on node\n\tif core.NodeID == node {\n\t\t// return the distance to itself (100%)\n\t\treturn st.Distances.cost(node, node)\n\t}\n\n\t// find a core on node to compare with\n\tfor _, target := range st.Cores {\n\t\tif target.NodeID == node {\n\t\t\treturn st.Distances.cost(target.NodeID, core.NodeID)\n\t\t}\n\t}\n\n\t// should not be possible\n\tpanic(\"topology: no node distance\")\n}\n\n// SupportsNUMA returns whether Nomad supports NUMA detection on the client's\n// operating system. Currently only supported on Linux.\nfunc (st *Topology) SupportsNUMA() bool {\n\tswitch runtime.GOOS {\n\tcase \"linux\":\n\t\treturn true\n\tdefault:\n\t\treturn false\n\t}\n}\n\n// GetNodes returns the set of NUMA Node IDs.\nfunc (st *Topology) GetNodes() *idset.Set[hw.NodeID] {\n\tif st.nodeIDs.Empty() {\n\t\tst.nodeIDs = idset.From[hw.NodeID](st.Nodes)\n\t}","sourceCodeStart":142,"sourceCodeEnd":178,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/client/lib/numalib/topology.go#L142-L178","documentation":"Topology.NodeDistance looks up the SLIT-style distance cost between two NUMA nodes by scanning st.Distances. If the target node ID is not found among the recorded distance entries, the invariant 'every node has a distance to every other node' is broken and the code panics with this message.","triggerScenarios":"Calling NodeDistance(node) where node is not present in the topology's Distances table — e.g. a core whose NodeID was not recorded during NUMA topology detection, or querying a node ID greater than the detected node count.","commonSituations":"Partial or failed NUMA detection on the host (no SLIT table, VM/container masking NUMA info) leaving an empty or incomplete Distances slice; calling NodeDistance before the topology has been fully populated; hardware/BIOS exposing cores mapped to an undeclared node.","solutions":["Call SupportsNUMA() and verify the topology was fully detected before invoking NodeDistance","Ensure the client's NUMA detection (numalib) ran on the host and populated Distances (check /sys/devices/system/node/slit or ACPI SLIT availability)","Guard call sites with a check that the requested node ID exists in the topology's node list","Report a bug with the host's NUMA topology — an internally inconsistent Topology is a detection bug"],"exampleFix":"// before\ncost := topo.NodeDistance(nodeID)\n// after\nif topo.SupportsNUMA() && nodeID < len(topo.Nodes) {\n    cost = topo.NodeDistance(nodeID)\n} else {\n    cost = defaultLocalCost\n}","handlingStrategy":"validation","validationCode":"func nodeExists(t *numalib.Topology, node uint64) bool {\n    for _, n := range t.GetDistances() { if n.NodeID == node { return true } }\n    return false\n}\n","typeGuard":null,"tryCatchPattern":"func safeNodeDistance(t *numalib.Topology, node int) (cost int, err error) {\n    defer func() {\n        if r := recover(); r != nil {\n            err = fmt.Errorf(\"no node distance for %d\", node)\n        }\n    }()\n    return t.NodeDistance(node), nil\n}\n","preventionTips":["Check SupportsNUMA() before NUMA-aware scheduling decisions","Verify NUMA detection succeeded (non-empty Distances) on the host","Guard calls with node-ID bounds checks against detected nodes"],"tags":["numa","topology","panic","invariant-violation"],"backgroundTag":"numa-topology-incomplete","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}