hashicorp/nomad · error
job ID must be set to set group
Error message
job ID must be set to set group
What it means
Within the JobACL validation block, Validate requires JobID to be set whenever Group is set — a group restriction is only meaningful relative to a specific job. The policy is rejected with 'job ID must be set to set group' and folded into the multierror.
Source
Thrown at nomad/structs/acl.go:388
if !ValidPolicyName.MatchString(a.Name) {
err := fmt.Errorf("invalid name '%s'", a.Name)
mErr.Errors = append(mErr.Errors, err)
}
if _, err := acl.Parse(a.Rules, acl.PolicyParseStrict); err != nil {
err = fmt.Errorf("failed to parse rules: %v", err)
mErr.Errors = append(mErr.Errors, err)
}
if len(a.Description) > maxPolicyDescriptionLength {
err := fmt.Errorf("description longer than %d", maxPolicyDescriptionLength)
mErr.Errors = append(mErr.Errors, err)
}
if a.JobACL != nil {
if a.JobACL.JobID != "" && a.JobACL.Namespace == "" {
err := fmt.Errorf("namespace must be set to set job ID")
mErr.Errors = append(mErr.Errors, err)
}
if a.JobACL.Group != "" && a.JobACL.JobID == "" {
err := fmt.Errorf("job ID must be set to set group")
mErr.Errors = append(mErr.Errors, err)
}
if a.JobACL.Task != "" && a.JobACL.Group == "" {
err := fmt.Errorf("group must be set to set task")
mErr.Errors = append(mErr.Errors, err)
}
}
return mErr.ErrorOrNil()
}
// ACLPolicyListStub is used to for listing ACL policies
type ACLPolicyListStub struct {
Name string
Description string
JobACL *JobACL
Hash []byte
CreateIndex uint64View on GitHub (pinned to 482b49bf1a)
Solutions
- Add the parent JobID to the JobACL block alongside Group.
- If cluster/group-wide access was intended, remove JobACL and grant the capability at namespace scope instead.
- Validate the policy JSON locally before submission to catch partial JobACL objects.
Example fix
// before
"JobACL": {"Namespace": "default", "Group": "web"}
// after
"JobACL": {"Namespace": "default", "JobID": "webapp", "Group": "web"} Defensive patterns
Strategy: validation
Validate before calling
func validateGroupACL(j *JobACL) error {
if j != nil && j.Group != "" && j.JobID == "" {
return errors.New("job ID must be set when Group is set")
}
return nil
} Type guard
func groupScopedCorrectly(j *structs.JobACL) bool {
return j == nil || j.Group == "" || j.JobID != ""
} Try / catch
if err := policy.Validate(); err != nil {
if strings.Contains(err.Error(), "job ID must be set to set group") {
return fmt.Errorf("JobACL.Group requires JobID: %w", err)
}
return err
} Prevention
- Remember Group scoping is always relative to a specific JobID — never cluster-wide.
- Build the JobACL hierarchy bottom-up: namespace -> job ID -> group -> task.
- If cluster-wide access is intended, use namespace capabilities instead of JobACL.
- Validate locally before every policy submission.
When it happens
Trigger: Submitting an ACL policy with JobACL.Group non-empty but JobACL.JobID empty, e.g. JSON {"JobACL":{"Namespace":"default","Group":"web"}} or templated apply where the job variable was empty.
Common situations: Authors assuming group-scoped rules work cluster-wide like namespace rules; copy-paste of a namespace-only policy then adding Group without JobID; automation that fills group from a task name but not the job.
Related errors
- namespace must be set to set job ID
- group must be set to set task
- errMissingACLRoleID
- errMissingACLAuthMethodName
- errMissingACLBindingRuleID
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/23ce5b3425ac1d29.
Report an issue: GitHub.