hashicorp/nomad · error
error parsing port label %q from service %q: %v
Error message
error parsing port label %q from service %q: %v
What it means
When registering group-level (agent) services, Nomad expects service.PortLabel to contain 'host:port' (agents do not use port labels directly). net.SplitHostPort failing on the label produces this error, embedding the original parse failure.
Source
Thrown at command/agent/consul/service_client.go:1225
// Script checks are not supported and will return an error. Registration is
// asynchronous.
//
// Agents will be deregistered when Shutdown is called.
//
// 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)
View on GitHub (pinned to 482b49bf1a)
Solutions
- Set the service's address/port via address_mode or use the interpolated form 'host:port' (e.g. ${NOMAD_IP_http}:${NOMAD_PORT_http}) in PortLabel.
- Ensure the interpolation resolves — the referenced port must exist so variables are not empty.
- For IPv6, bracket the host part ([fd00::1]:8080) so SplitHostPort succeeds.
Example fix
// before
service {
name = "api"
port = "http" // bare label for group service
}
// after
service {
name = "api"
port = "http"
provider = "consul"
address_mode = "host" // or use ${NOMAD_IP_http}:${NOMAD_PORT_http}
} Defensive patterns
Strategy: validation
Validate before calling
if _, _, err := net.SplitHostPort(service.PortLabel); err != nil {
return fmt.Errorf("service %q: PortLabel %q must be host:port", service.Name, service.PortLabel)
} Type guard
func isHostPort(label string) bool {
_, _, err := net.SplitHostPort(label)
return err == nil
} Prevention
- For agent services use host:port, not bare port labels.
- Prefer address_mode over manual interpolation where possible.
- Bracket IPv6 hosts in address:port strings.
When it happens
Trigger: Registering a service whose PortLabel is not of the form address:port — e.g. a bare port label like 'http' instead of '${NOMAD_IP_http}:${NOMAD_PORT_http}', or an IPv6 literal without brackets.
Common situations: Bridge/network-mode jobs using a plain port label for a group service; interpolation producing an empty string; IPv6 addresses passed unbracketed into SplitHostPort.
Related errors
- invalid port %q: port label not found or is not numeric
- No port of label %q defined
- error parsing port %q from service %q: %v
- service %q contains invalid check: agent checks do not suppo
- error parsing port label %q from check %q: %v
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/e39017eafcfd79b2.
Report an issue: GitHub.