hashicorp/nomad · error
Semver affinity is invalid: %v
Error message
Semver affinity is invalid: %v
What it means
This error comes from Affinity.Validate() in nomad/structs/structs.go. When an affinity uses the 'semver' operator (ConstraintSemver), Nomad parses the affinity's RTarget with hashicorp/go-version's semver.NewConstraint. If the target string is not a valid semver constraint, validation fails with 'Semver affinity is invalid: <parse error>'. It exists to catch malformed version constraints at job-submission time rather than at scheduling time.
Source
Thrown at nomad/structs/structs.go:10216
}
// 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"))
}
// Ensure that weight is between -100 and 100, and not zero
if a.Weight == 0 {
mErr.Errors = append(mErr.Errors, fmt.Errorf("Affinity weight cannot be zero"))
}View on GitHub (pinned to 482b49bf1a)
Solutions
- Fix the RTarget to be a valid semver constraint accepted by hashicorp/go-version's semver.NewConstraint (e.g. "~> 1.2.0", ">= 1.2, < 2.0").
- If you need non-semver range syntax (like "1.x"), use the "version" operator instead of "semver".
- Ensure RTarget is non-empty when operand is "semver".
Example fix
// before
affinity {
attribute = "attr.meta.app_version"
operator = "semver"
value = "1.x"
}
// after
affinity {
attribute = "attr.meta.app_version"
operator = "semver"
value = "~> 1.0"
} Defensive patterns
Strategy: validation
Validate before calling
func validSemverConstraint(s string) bool { _, err := semver.NewConstraint(s); return err == nil }
// before submit: check every affinity with operand "semver" Type guard
func isSemverOperand(op string) bool { return op == "semver" } Prevention
- Lint job specs against hashicorp/go-version semver syntax before nomad job run
- Prefer the "version" operator when you need non-semver range syntax
- Never leave value empty on a semver affinity
When it happens
Trigger: Submitting a job (via nomad job run / /v1/jobs API) whose task/group affinity has operand "semver" and an RTarget that fails semver.NewConstraint, e.g. "~> 2" with invalid spacing, "1.x", "latest", or an empty RTarget.
Common situations: Copy-pasting npm-style version ranges (which go-version's semver parser does not accept), typos like "v1.2..3", forgetting to quote ranges in HCL, or switching an affinity from "version" to "semver" without adjusting the constraint syntax.
Related errors
- Unknown affinity operator %q
- No LTarget provided but is required
- Affinity weight cannot be zero
- Affinity weight must be within the range [-100,100]
- Disconnect cannot be configured with both lost_after and sto
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/450554778cf9a3ce.
Report an issue: GitHub.