hashicorp/nomad · error

Set contains constraint requires an RTarget

Error message

Set contains constraint requires an RTarget

What it means

Constraints using set-contains operands (set_contains, set_contains_all, set_contains_any) require a non-empty RTarget listing the set membership values to check against. An empty RTarget makes the constraint meaningless, so validation fails.

Source

Thrown at nomad/structs/structs.go:10070

}

func (c *Constraint) Validate() error {
	var mErr multierror.Error
	if c.Operand == "" {
		mErr.Errors = append(mErr.Errors, errors.New("Missing constraint operand"))
	}

	// requireLtarget specifies whether the constraint requires an LTarget to be
	// provided.
	requireLtarget := true

	// Perform additional validation based on operand
	switch c.Operand {
	case ConstraintDistinctHosts:
		requireLtarget = false
	case ConstraintSetContainsAll, ConstraintSetContainsAny, ConstraintSetContains:
		if c.RTarget == "" {
			mErr.Errors = append(mErr.Errors, fmt.Errorf("Set contains constraint requires an RTarget"))
		}
	case ConstraintRegex:
		if _, err := regexp.Compile(c.RTarget); err != nil {
			mErr.Errors = append(mErr.Errors, fmt.Errorf("Regular expression failed to compile: %v", err))
		}
	case ConstraintVersion:
		if _, err := version.NewConstraint(c.RTarget); err != nil {
			mErr.Errors = append(mErr.Errors, fmt.Errorf("Version constraint is invalid: %v", err))
		}
	case ConstraintSemver:
		if _, err := semver.NewConstraint(c.RTarget); err != nil {
			mErr.Errors = append(mErr.Errors, fmt.Errorf("Semver constraint is invalid: %v", err))
		}
	case ConstraintDistinctProperty:
		// If a count is set, make sure it is convertible to a uint64
		if c.RTarget != "" {
			count, err := strconv.ParseUint(c.RTarget, 10, 64)
			if err != nil {

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Add a value listing items, e.g. constraint { operand = "set_contains", attribute = "${meta.roles}", value = "web" }.
  2. Remove the constraint if it is not needed.
  3. Check job-submission code paths so the RTarget is always populated for set-contains operands.

Example fix

// before
constraint {
  operand   = "set_contains"
  attribute = "${node.meta.roles}"
}
// after
constraint {
  operand   = "set_contains"
  attribute = "${node.meta.roles}"
  value     = "web"
}
Defensive patterns

Strategy: validation

Validate before calling

if operand == "set_contains" || operand == "set_contains_all" || operand == "set_contains_any" {
    if value == "" { return errors.New("set-contains constraint requires a value") }
}

Prevention

When it happens

Trigger: constraint { operand = "set_contains" } with no 'value'/'rtarget' field set, or value = "" — e.g. generated HCL where the attribute was dropped.

Common situations: Programmatic job generation omitting the value for set-contains constraints; hand-written constraints copying the distinct_hosts form (which needs no ltarget/rtarget pair semantics); refactors that rename fields and lose the value.

Related errors


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