hashicorp/nomad · error

Version affinity is invalid: %v

Error message

Version affinity is invalid: %v

What it means

An affinity with operand "version" has an RTarget that hashicorp/go-version's NewConstraint cannot parse. Unlike the constraint counterpart, the message says "Version affinity", but the cause is identical: the version expression is malformed. Job submission is rejected by validation.

Source

Thrown at nomad/structs/structs.go:10212

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

	// Perform additional validation based on operand
	switch a.Operand {
	case ConstraintSetContainsAll, ConstraintSetContainsAny, ConstraintSetContains:
		if a.RTarget == "" {
			mErr.Errors = append(mErr.Errors, fmt.Errorf("Set contains operators require an RTarget"))
		}
	case ConstraintRegex:
		if _, err := regexp.Compile(a.RTarget); err != nil {
			mErr.Errors = append(mErr.Errors, fmt.Errorf("Regular expression failed to compile: %v", err))
		}
	case ConstraintVersion:
		if _, err := version.NewConstraint(a.RTarget); err != nil {
			mErr.Errors = append(mErr.Errors, fmt.Errorf("Version affinity is invalid: %v", err))
		}
	case ConstraintSemver:
		if _, err := semver.NewConstraint(a.RTarget); err != nil {
			mErr.Errors = append(mErr.Errors, fmt.Errorf("Semver affinity is invalid: %v", err))
		}
	case "=", "==", "is", "!=", "not", "<", "<=", ">", ">=":
		if a.RTarget == "" {
			mErr.Errors = append(mErr.Errors, fmt.Errorf("Operator %q requires an RTarget", a.Operand))
		}
	default:
		mErr.Errors = append(mErr.Errors, fmt.Errorf("Unknown affinity operator %q", a.Operand))
	}

	// Ensure we have an LTarget
	if a.LTarget == "" {
		mErr.Errors = append(mErr.Errors, fmt.Errorf("No LTarget provided but is required"))
	}

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Rewrite the RTarget in valid go-version syntax, e.g. ">= 1.2.0" or ">= 1.2, < 2.0".
  2. Pre-validate with version.NewConstraint(target) before submission.
  3. Use nomad job validate to catch the malformed expression early.

Example fix

// before
affinity {
  attribute = "${attr.driver.docker.version}"
  operand   = "version"
  value     = ">= 20.10.x"
}
// after
affinity {
  attribute = "${attr.driver.docker.version}"
  operand   = "version"
  value     = ">= 20.10.0"
}
Defensive patterns

Strategy: validation

Validate before calling

import "github.com/hashicorp/go-version"

func validAffinityVersion(target string) bool {
  _, err := version.NewConstraint(target)
  return err == nil
}

Try / catch

if _, err := version.NewConstraint(target); err != nil {
  return fmt.Errorf("invalid version affinity %q: %w", target, err)
}

Prevention

When it happens

Trigger: Submitting an affinity with operand "version" and RTarget like ">= 1.x.y!", "1.2.3.4", "v>= 1.2 ," (trailing comma), or other malformed comparator lists.

Common situations: Typos in version ranges in templated jobs; concatenating version strings programmatically producing invalid expressions; using SemVer-only or npm-style range syntax unsupported by go-version; copy-paste with stray whitespace/commas.

Related errors


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