hashicorp/nomad · error

error parsing port %q from service %q: %v

Error message

error parsing port %q from service %q: %v

What it means

Immediately after successfully splitting the PortLabel, the port component must parse as an integer via strconv.Atoi. If the port substring is non-numeric (bad interpolation, garbage in the label), this error is returned with the raw port, service name, and underlying error.

Source

Thrown at command/agent/consul/service_client.go:1229

//
// Note: no need to manually plumb Consul namespace into the agent service registration
// or its check registrations, because the Nomad Client's Consul Client will already
// have the Nomad Client's Consul Namespace set on startup.
func (c *ServiceClient) RegisterAgent(role string, services []*structs.Service) error {
	ops := operations{}

	for _, service := range services {
		id := makeAgentServiceID(role, service)

		// Unlike tasks, agents don't use port labels. Agent ports are
		// stored directly in the PortLabel.
		host, rawport, err := net.SplitHostPort(service.PortLabel)
		if err != nil {
			return fmt.Errorf("error parsing port label %q from service %q: %v", service.PortLabel, service.Name, err)
		}
		port, err := strconv.Atoi(rawport)
		if err != nil {
			return fmt.Errorf("error parsing port %q from service %q: %v", rawport, service.Name, err)
		}
		serviceReg := &api.AgentServiceRegistration{
			ID:      id,
			Name:    service.Name,
			Tags:    service.Tags,
			Address: host,
			Port:    port,
			// This enables the consul UI to show that Nomad registered this service
			Meta: map[string]string{
				"external-source": "nomad",
			},
		}
		ops.regServices = append(ops.regServices, serviceReg)

		// older agents use SHA-1 hashes as part of the service name instead of
		// SHA-256, but we can't guarantee they've shutdown gracefully and
		// deregistered themselves on upgrade. Remove any legacy service IDs
		// that might be lingering

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Ensure the interpolated port variable (e.g. ${NOMAD_PORT_http}) refers to a numeric, allocated port.
  2. Fix or remove malformed characters in the PortLabel so the port segment is a plain integer.
  3. Validate the job spec and inspect the rendered template to confirm resolved values.

Example fix

// before
port = "${NOMAD_HOST_IP_http}:${NOMAD_PORT_name}" // wrong var -> non-numeric port
// after
port = "${NOMAD_IP_http}:${NOMAD_PORT_http}"
Defensive patterns

Strategy: validation

Validate before calling

_, rawport, err := net.SplitHostPort(label)
if err != nil { return err }
if _, err := strconv.Atoi(rawport); err != nil {
  return fmt.Errorf("port %q is not numeric", rawport)
}

Type guard

func isNumericPort(raw string) bool {
  p, err := strconv.Atoi(raw)
  return err == nil && p > 0 && p < 65536
}

Prevention

When it happens

Trigger: service.PortLabel contains a host:port whose port field is not a valid integer — e.g. unresolved '${...}' leftovers, letters, or a trailing colon producing an empty rawport.

Common situations: Malformed NOMAD_PORT_* interpolation, jobs where the port variable resolves to a name rather than a number, hand-written address:port strings with typos.

Related errors


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