hashicorp/nomad · error
Services are not unique: %s
Error message
Services are not unique: %s
What it means
During TaskGroup validation in nomad/structs/structs.go, Nomad collects services whose <task, name, port> tuple is duplicated within the group and fails validation. Job specs must have unique service identity per task/name/port combination so that service registration and discovery are unambiguous.
Source
Thrown at nomad/structs/structs.go:7559
for _, check := range service.Checks {
if check.TaskName != "" {
if check.AddressMode == AddressModeDriver {
mErr.Errors = append(mErr.Errors, fmt.Errorf("Check %q invalid: cannot use address_mode=\"driver\", only checks defined in a \"task\" service block can use this mode", service.Name))
}
if !taskSet.Contains(check.TaskName) {
mErr.Errors = append(mErr.Errors,
fmt.Errorf("Check %s invalid: refers to non-existent task %s", check.Name, check.TaskName))
}
}
}
}
// Produce an error of any services which are not unique enough in the group
// i.e. have same <task, name, port>
if idDuplicateSet.Size() > 0 {
mErr.Errors = append(mErr.Errors,
fmt.Errorf(
"Services are not unique: %s",
idDuplicateSet.StringFunc(
func(u unique) string {
s := u.task + "->" + u.name
if u.port != "" {
s += ":" + u.port
}
return s
},
),
),
)
}
// The initial feature release of native service discovery only allows for
// a single service provider to be used across all services in a task
// group.
if providerSet.Size() > 1 {View on GitHub (pinned to 482b49bf1a)
Solutions
- Rename one of the duplicate services so each <task, name, port> tuple is unique
- If you only need more checks, move the extra checks into the existing service's `check` blocks instead of duplicating the service
- Parameterize your template/generator so service names include the task or port they target
Example fix
// before
service { name = "web" port = "http" }
service { name = "web" port = "http" }
// after
service {
name = "web"
port = "http"
check { type = "http" path = "/health" }
} Defensive patterns
Strategy: validation
Validate before calling
names := map[string]bool{}
for _, svc := range group.Services {
key := svc.Task + "->" + svc.Name + ":" + svc.Port
if names[key] { return fmt.Errorf("duplicate service %q", key) }
names[key] = true
} Type guard
func uniqueServices(svcs []*api.Service) bool {
seen := map[string]bool{}
for _, s := range svcs {
k := s.TaskName + "->" + s.Name + ":" + s.PortLabel
if seen[k] { return false }
seen[k] = true
}
return true
} Prevention
- Add a CI step running `nomad job validate` on every job file
- Generate service names from task+port in templates to guarantee uniqueness
- Consolidate multiple checks into one service block
When it happens
Trigger: Submitting a job where a task group (or its tasks) declares two services with the same name pointing at the same task and the same port label — e.g. two `service { name = "http" port = "http" }` blocks attached to the same task.
Common situations: Copy-pasting a service block to add a second check instead of adding checks to the existing service; templating loops that generate services with an identical name; forgetting that group-level and task-level services share the uniqueness constraint.
Related errors
- Task group service validation failed: %v
- Task group service check validation failed: %v
- ErrConnectRequireOneNetwork
- ErrConnectInvalidNetworkMode
- service.port must be set for mesh gateway service
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/fc407270c4032d68.
Report an issue: GitHub.