hashicorp/nomad · error
Job datacenter must be non-empty string
Error message
Job datacenter must be non-empty string
What it means
When j.Datacenters is non-empty, Job.Validate() iterates the list and rejects any empty-string entry. Every datacenter name must be a non-empty string so the scheduler can match it against node datacenter labels.
Source
Thrown at nomad/structs/structs.go:4771
mErr.Errors = append(mErr.Errors, errors.New("Job Name contains a null character"))
}
if j.Namespace == "" {
mErr.Errors = append(mErr.Errors, errors.New("Job must be in a namespace"))
}
switch j.Type {
case JobTypeCore, JobTypeService, JobTypeBatch, JobTypeSystem, JobTypeSysBatch:
case "":
mErr.Errors = append(mErr.Errors, errors.New("Missing job type"))
default:
mErr.Errors = append(mErr.Errors, fmt.Errorf("Invalid job type: %q", j.Type))
}
if len(j.Datacenters) == 0 && !j.IsMultiregion() {
mErr.Errors = append(mErr.Errors, errors.New("Missing job datacenters"))
} else {
for _, v := range j.Datacenters {
if v == "" {
mErr.Errors = append(mErr.Errors, errors.New("Job datacenter must be non-empty string"))
}
}
}
if len(j.TaskGroups) == 0 {
mErr.Errors = append(mErr.Errors, errors.New("Missing job task groups"))
}
for idx, constr := range j.Constraints {
if err := constr.Validate(); err != nil {
outer := fmt.Errorf("Constraint %d validation failed: %s", idx+1, err)
mErr.Errors = append(mErr.Errors, outer)
}
}
if j.Type == JobTypeSystem {
if j.Affinities != nil {
mErr.Errors = append(mErr.Errors, fmt.Errorf("System jobs may not have an affinity block"))
}
} else {View on GitHub (pinned to 482b49bf1a)
Solutions
- Remove empty entries from the datacenters list, keeping only valid names
- Fix the template/variable that renders empty and add a non-empty guard
- Filter with a helper before submission (keep only trimmed non-empty values)
Example fix
// before
datacenters = ["dc1", "${extra_dc}"]
// after
datacenters = ["dc1"]
// or ensure ${extra_dc} resolves to a real datacenter name Defensive patterns
Strategy: validation
Validate before calling
cleaned := make([]string, 0, len(j.Datacenters))
for _, dc := range j.Datacenters {
if strings.TrimSpace(dc) != "" { cleaned = append(cleaned, dc) }
}
j.Datacenters = cleaned Type guard
func hasValidDatacenters(dcs []string) bool {
for _, dc := range dcs { if strings.TrimSpace(dc) == "" { return false } }
return len(dcs) > 0
} Try / catch
if err := job.Validate(); err != nil {
if strings.Contains(err.Error(), "datacenter must be non-empty") {
return fmt.Errorf("remove empty entries from the datacenters list: %w", err)
}
} Prevention
- Filter templated datacenter lists for empty renders before submission
- Avoid trailing commas / whitespace-only entries in hand-written lists
- Validate templates so variables feeding datacenters never resolve empty
When it happens
Trigger: Submitting a job with datacenters = ["dc1", ""] or with a template variable that renders empty inside the list; constructing structs.Job with an empty-string element in Datacenters.
Common situations: Templating like datacenters = ["${dc}"] where ${dc} resolves to ""; trailing commas or whitespace-only entries after string processing; merging config files that append an empty entry.
Related errors
- Missing job datacenters
- Missing job ID
- Job ID contains a space
- Job ID contains a null character
- Missing job name
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/9679ca9bfd105597.
Report an issue: GitHub.