hashicorp/nomad · error

group must be set to set task

Error message

group must be set to set task

What it means

The JobACL chain ends with: Task requires Group to be set. A task-level restriction must sit inside a named group inside a named job, so Validate rejects policies where JobACL.Task is non-empty while JobACL.Group is empty, appending 'group must be set to set task'.

Source

Thrown at nomad/structs/acl.go:392

	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 uint64
	ModifyIndex uint64
}

// ACLPolicyListRequest is used to request a list of policies

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Provide the containing Group in the JobACL block (namespace + job ID + group + task).
  2. If task-level scoping is not required, drop Task and scope to the group or job instead.
  3. Construct the full hierarchy programmatically rather than field-by-field to keep it consistent.

Example fix

// before
"JobACL": {"Namespace": "default", "JobID": "webapp", "Task": "server"}
// after
"JobACL": {"Namespace": "default", "JobID": "webapp", "Group": "web", "Task": "server"}
Defensive patterns

Strategy: validation

Validate before calling

func validateTaskACL(j *JobACL) error {
    if j != nil && j.Task != "" && j.Group == "" {
        return errors.New("group must be set when Task is set")
    }
    return nil
}

Type guard

func taskScopedCorrectly(j *structs.JobACL) bool {
    return j == nil || j.Task == "" || j.Group != ""
}

Try / catch

if err := policy.Validate(); err != nil {
    if strings.Contains(err.Error(), "group must be set to set task") {
        return fmt.Errorf("JobACL.Task requires Group: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: Submitting an ACL policy with JobACL.Task set but JobACL.Group empty — e.g. JSON {"JobACL":{"Namespace":"default","JobID":"webapp","Task":"server"}}.

Common situations: Building the JobACL object incrementally and forgetting the intermediate group level; assuming tasks can be targeted by name alone; generated policies where group name resolution failed but task name succeeded.

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/8fd41574827e3eb6. Report an issue: GitHub.