hashicorp/nomad · error
error parsing port label %q from check %q: %v
Error message
error parsing port label %q from check %q: %v
What it means
When registering an agent service, each non-empty check PortLabel is parsed with net.SplitHostPort to obtain host:port. This error wraps the SplitHostPort error (e.g. 'missing port in address' or 'too many colons in address') when the check's PortLabel is not a valid host:port pair. Unlike task services, agent checks must encode the port directly in the label, so any malformed value aborts registration.
Source
Thrown at command/agent/consul/service_client.go:1269
legacyID := service.LegacyAgentID(role)
if legacyID != "" {
// we intentionally swallow this error because these services likely
// no longer exist
_ = c.agentAPI.ServiceDeregisterOpts(legacyID, nil)
}
for _, check := range service.Checks {
checkID := MakeCheckID(id, check)
if check.Type == structs.ServiceCheckScript {
return fmt.Errorf("service %q contains invalid check: agent checks do not support scripts", service.Name)
}
checkHost, checkPort := serviceReg.Address, serviceReg.Port
if check.PortLabel != "" {
// Unlike tasks, agents don't use port labels. Agent ports are
// stored directly in the PortLabel.
host, rawport, err := net.SplitHostPort(check.PortLabel)
if err != nil {
return fmt.Errorf("error parsing port label %q from check %q: %v", service.PortLabel, check.Name, err)
}
port, err := strconv.Atoi(rawport)
if err != nil {
return fmt.Errorf("error parsing port %q from check %q: %v", rawport, check.Name, err)
}
checkHost, checkPort = host, port
}
checkReg, err := createCheckReg(id, checkID, check, checkHost, checkPort, "")
if err != nil {
return fmt.Errorf("failed to add check %q: %v", check.Name, err)
}
ops.regChecks = append(ops.regChecks, checkReg)
}
}
// Don't bother committing agent checks if we're already shutting down
c.agentLock.Lock()
defer c.agentLock.Unlock()View on GitHub (pinned to 482b49bf1a)
Solutions
- Set the check's PortLabel to an explicit 'host:port' value, e.g. '127.0.0.1:4646', instead of a Nomad port label name
- Check the wrapped %v error to distinguish 'missing port' (add :port) from 'too many colons' (bracket IPv6 like [::1]:4646)
- Remove the port_label key entirely so the check inherits the service registration address/port
- Audit other checks on the same agent service for the same malformed label
Example fix
// before (agent config)
check {
type = "http"
port_label = "http"
}
// after
check {
type = "http"
port_label = "127.0.0.1:4646"
} Defensive patterns
Strategy: validation
Validate before calling
// Validate check port labels are host:port before applying agent config
_, _, err := net.SplitHostPort(check.PortLabel)
if err != nil {
return fmt.Errorf("check %q port_label %q must be host:port", check.Name, check.PortLabel)
} Type guard
func isValidHostPort(label string) bool {
host, port, err := net.SplitHostPort(label)
return err == nil && host != "" && port != ""
} Prevention
- Agent checks use raw host:port, not Nomad port labels — remember the difference
- Bracket IPv6 literals: [::1]:4646
- Test with `net.SplitHostPort` before deploying config
- Omit port_label to inherit the service registration address
When it happens
Trigger: RegisterAgentWorkload with a check whose PortLabel is a bare port label (e.g. 'http') or otherwise lacks a 'host:port' form, so net.SplitHostPort returns an error; IPv6 literals not bracketed correctly also trigger 'too many colons'.
Common situations: Setting check.port_label = "http" (a task-style port label) in agent config where a raw 'host:port' like "127.0.0.1:4646" is required; copy-pasted task service config; forgetting the port entirely.
Related errors
- No port of label %q defined
- error parsing port label %q from service %q: %v
- unable to get address for service %q: %v
- error creating bootstrap configuration for Connect proxy sid
- client stopped and may not longer create config entries
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/82452b471cfb81b7.
Report an issue: GitHub.