hashicorp/nomad · error
reserved port collision %s=%d
Error message
reserved port collision %s=%d
What it means
AssignPorts could not allocate a requested reserved port because that port on the candidate host address is already reserved by another allocation on the same node. Nomad tracks used ports per IP via a bitset (getUsedPortsFor); when a requested static port collides and the port is not marked IgnoreCollision, the address is skipped and this error is returned. It indicates host port contention on a particular network interface.
Source
Thrown at nomad/structs/network.go:494
for _, port := range ask.ReservedPorts {
reservedIdx[port.HostNetwork] = append(reservedIdx[port.HostNetwork], port)
// allocPort is set in the inner for loop if a port mapping can be created
// if allocPort is still nil after the loop, the port wasn't available for reservation
var allocPort *AllocatedPortMapping
var addrErr error
for _, addr := range idx.HostNetworks[port.HostNetwork] {
// Guard against invalid port
if port.Value < 0 || port.Value >= MaxValidPort {
return nil, fmt.Errorf("invalid port %d (out of range)", port.Value)
}
// Check if in use
if !port.IgnoreCollision {
used := idx.getUsedPortsFor(addr.Address)
if used != nil && used.Check(uint(port.Value)) {
addrErr = fmt.Errorf("reserved port collision %s=%d", port.Label, port.Value)
continue
}
}
allocPort = &AllocatedPortMapping{
Label: port.Label,
Value: port.Value,
To: port.To,
HostIP: addr.Address,
IgnoreCollision: port.IgnoreCollision,
}
break
}
if allocPort == nil {
if addrErr != nil {
return nil, addrErr
}View on GitHub (pinned to 482b49bf1a)
Solutions
- Change the task's static reserved port to a free value or switch to a dynamic port (omit Value / use a port range).
- Move the task to a host_network with fewer allocations so the port is free on that interface.
- Set IgnoreCollision: true on the port if co-existence is safe in your environment.
- Spread static-port workloads across client nodes to reduce per-node contention.
Example fix
// before
ReservedPorts: [{Label: "http", Value: 8080}]
// after
ReservedPorts: [{Label: "http", Static: 0, To: 8080}] // dynamic host port mapped to container 8080 Defensive patterns
Strategy: validation
Validate before calling
// before submitting a job with static ports, check they're free on the target host
func validateStaticPortsFree(ports []int, host string) error {
for _, p := range ports {
if p < 1 || p > 65535 { return fmt.Errorf("port %d out of range", p) }
ln, err := net.Listen("tcp", fmt.Sprintf("%s:%d", host, p))
if err != nil { return fmt.Errorf("port %d in use", p) }
ln.Close()
}
return nil
} Type guard
func isValidPort(p int) bool { return p > 0 && p < 65536 } Try / catch
null
Prevention
- Prefer dynamic ports unless a well-known port is genuinely required
- Keep a registry of static ports per node to avoid duplicate pins
- Use distinct host_networks for workloads needing the same static port
When it happens
Trigger: Calling NetworkIndex.AssignPorts with a NetworkResource whose ReservedPorts (or HostNetwork-reserved ports) include a port number already in the index's used set for that address; the port's IgnoreCollision flag is false.
Common situations: Two jobs on the same node request static port 8080; a service hardcodes well-known ports (80, 443) that the host already uses; re-scheduling after a stale allocation still holds the port in the index.
Related errors
- no addresses available for %s network
- no networks available
- network namespace already exists but was misconfigured
- network already configured but not found in state
- no CNI network config found
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/0982f91760107384.
Report an issue: GitHub.