{"record":{"id":"d81d62930eaa0c92","repo":"hashicorp/nomad","slug":"version-affinity-is-invalid-v","errorCode":null,"errorMessage":"Version affinity is invalid: %v","messagePattern":"Version affinity is invalid: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/structs/structs.go","lineNumber":10212,"sourceCode":"func (a *Affinity) Validate() error {\n\tvar mErr multierror.Error\n\tif a.Operand == \"\" {\n\t\tmErr.Errors = append(mErr.Errors, errors.New(\"Missing affinity operand\"))\n\t}\n\n\t// Perform additional validation based on operand\n\tswitch a.Operand {\n\tcase ConstraintSetContainsAll, ConstraintSetContainsAny, ConstraintSetContains:\n\t\tif a.RTarget == \"\" {\n\t\t\tmErr.Errors = append(mErr.Errors, fmt.Errorf(\"Set contains operators require an RTarget\"))\n\t\t}\n\tcase ConstraintRegex:\n\t\tif _, err := regexp.Compile(a.RTarget); err != nil {\n\t\t\tmErr.Errors = append(mErr.Errors, fmt.Errorf(\"Regular expression failed to compile: %v\", err))\n\t\t}\n\tcase ConstraintVersion:\n\t\tif _, err := version.NewConstraint(a.RTarget); err != nil {\n\t\t\tmErr.Errors = append(mErr.Errors, fmt.Errorf(\"Version affinity is invalid: %v\", err))\n\t\t}\n\tcase ConstraintSemver:\n\t\tif _, err := semver.NewConstraint(a.RTarget); err != nil {\n\t\t\tmErr.Errors = append(mErr.Errors, fmt.Errorf(\"Semver affinity is invalid: %v\", err))\n\t\t}\n\tcase \"=\", \"==\", \"is\", \"!=\", \"not\", \"<\", \"<=\", \">\", \">=\":\n\t\tif a.RTarget == \"\" {\n\t\t\tmErr.Errors = append(mErr.Errors, fmt.Errorf(\"Operator %q requires an RTarget\", a.Operand))\n\t\t}\n\tdefault:\n\t\tmErr.Errors = append(mErr.Errors, fmt.Errorf(\"Unknown affinity operator %q\", a.Operand))\n\t}\n\n\t// Ensure we have an LTarget\n\tif a.LTarget == \"\" {\n\t\tmErr.Errors = append(mErr.Errors, fmt.Errorf(\"No LTarget provided but is required\"))\n\t}\n","sourceCodeStart":10194,"sourceCodeEnd":10230,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/structs/structs.go#L10194-L10230","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Rewrite the RTarget in valid go-version syntax, e.g. \">= 1.2.0\" or \">= 1.2, < 2.0\".","Pre-validate with version.NewConstraint(target) before submission.","Use nomad job validate to catch the malformed expression early."],"exampleFix":"// before\naffinity {\n  attribute = \"${attr.driver.docker.version}\"\n  operand   = \"version\"\n  value     = \">= 20.10.x\"\n}\n// after\naffinity {\n  attribute = \"${attr.driver.docker.version}\"\n  operand   = \"version\"\n  value     = \">= 20.10.0\"\n}","handlingStrategy":"validation","validationCode":"import \"github.com/hashicorp/go-version\"\n\nfunc validAffinityVersion(target string) bool {\n  _, err := version.NewConstraint(target)\n  return err == nil\n}","typeGuard":null,"tryCatchPattern":"if _, err := version.NewConstraint(target); err != nil {\n  return fmt.Errorf(\"invalid version affinity %q: %w\", target, err)\n}","preventionTips":["Use go-version range grammar only; no npm/cargo range syntax.","Sanitize templated version strings for stray commas/whitespace.","Run nomad job validate in the deployment pipeline."],"tags":["nomad","affinity","version-parsing","job-validation"],"backgroundTag":"invalid-version-constraint","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}