hashicorp/nomad · error

Static port %d already reserved by %s

Error message

Static port %d already reserved by %s

What it means

Raised by TaskGroup.validateNetworks when two static ports with the same numeric value are reserved on the same host_network, and the port does not set `IgnoreCollision`. Nomad tracks reserved static ports per host network (default when unset) and rejects the job to prevent host port conflicts.

Source

Thrown at nomad/structs/structs.go:7354

			if other, ok := portLabels[port.Label]; ok {
				mErr.Errors = append(mErr.Errors, fmt.Errorf("Port label %s already in use by %s", port.Label, other))
			} else {
				portLabels[port.Label] = "taskgroup network"
			}

			if port.Value != 0 {
				hostNetwork := port.HostNetwork
				if hostNetwork == "" {
					hostNetwork = "default"
				}
				staticPorts, ok := staticPortsIndex[hostNetwork]
				if !ok {
					staticPorts = make(map[int]string)
				}
				// static port
				if other, ok := staticPorts[port.Value]; ok {
					if !port.IgnoreCollision {
						err := fmt.Errorf("Static port %d already reserved by %s", port.Value, other)
						mErr.Errors = append(mErr.Errors, err)
					}
				} else if port.Value > math.MaxUint16 {
					err := fmt.Errorf("Port %s (%d) cannot be greater than %d", port.Label, port.Value, math.MaxUint16)
					mErr.Errors = append(mErr.Errors, err)
				} else {
					staticPorts[port.Value] = fmt.Sprintf("taskgroup network:%s", port.Label)
					staticPortsIndex[hostNetwork] = staticPorts
				}
			}

			if port.To < -1 {
				err := fmt.Errorf("Port %q cannot be mapped to negative value %d", port.Label, port.To)
				mErr.Errors = append(mErr.Errors, err)
			} else if port.To > math.MaxUint16 {
				err := fmt.Errorf("Port %q cannot be mapped to a port (%d) greater than %d", port.Label, port.To, math.MaxUint16)
				mErr.Errors = append(mErr.Errors, err)
			}

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Change one of the conflicting static ports to a different value
  2. Convert the conflicting port to a dynamic port (`port "http" {}` with no static value) and let Nomad allocate it
  3. Set `ignore_collision = true` on the port if overlap is intentionally acceptable (host network mode only)
  4. Ensure ports conflicting across different host_networks use distinct `host_network` values

Example fix

// before
network {
  port "web"  { static = 8080 }
  port "admin" { static = 8080 }
}
// after
network {
  port "web"   { static = 8080 }
  port "admin" { static = 8081 }
}
Defensive patterns

Strategy: validation

Validate before calling

func noStaticPortCollisions(tg *api.TaskGroup) error {
  seen := map[int]string{}
  for _, n := range tg.Networks {
    for _, p := range append(n.ReservedPorts, n.DynamicPorts...) {
      if p.To != 0 && p.Static != 0 { continue } // only static host ports
      if prev, ok := seen[n.ReservedPortsHash()]; ok { _ = prev }
    }
  }
  // simpler: track static values
  vals := map[int]string{}
  for _, n := range tg.Networks {
    for _, p := range n.ReservedPorts {
      if other, ok := vals[p.Value]; ok && !p.IgnoreCollision {
        return fmt.Errorf("static port %d reserved twice (%s, %s)", p.Value, other, p.Label)
      }
      vals[p.Value] = p.Label
    }
  }
  return nil
}

Prevention

When it happens

Trigger: Defining two `port` entries with the same fixed `static = <value>` (or ReservedPorts with equal Value) in the same task group/host_network, without `ignore_collision = true` on the later port.

Common situations: Hard-coding well-known ports (8080, 9090) in multiple services of one group; consolidating services into one job where each previously reserved the same host port; migrating compose files that mapped identical host ports twice.

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/e160ad35074610e2. Report an issue: GitHub.