{"record":{"id":"04bab5902faba544","repo":"hashicorp/nomad","slug":"attribute-q-is-missing-a-closing-brace","errorCode":null,"errorMessage":"attribute %q is missing a closing brace","messagePattern":"attribute %q is missing a closing brace","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/structs/constraint.go","lineNumber":47,"sourceCode":")\n\n// validateConstraintAttribute ensures the constraint attribute is valid. It\n// does this by ensuring any interpolated field can be handled by the\n// resolveTarget function.\nfunc validateConstraintAttribute(target string) error {\n\n\t// If no prefix delimieter is included, we assume this is a literal value\n\t// and is therefore valid.\n\tif !strings.HasPrefix(target, \"$\") {\n\t\treturn nil\n\t}\n\n\t// Must have the correct opening and closing delimeters.\n\tif !strings.HasPrefix(target, \"${\") {\n\t\treturn fmt.Errorf(\"attribute %q is missing an opening brace\", target)\n\t}\n\tif !strings.HasSuffix(target, \"}\") {\n\t\treturn fmt.Errorf(\"attribute %q is missing a closing brace\", target)\n\t}\n\n\t// Perform our exact target matching first. If the target does not hit this\n\t// exact match, we will fall through to the prefix match check.\n\tif slices.Contains(validConstraintExactTargets, target) {\n\t\treturn nil\n\t}\n\n\t// Check the target against our valid prefixes.\n\tfor _, prefix := range validConstraintPrefixTargets {\n\t\tif strings.HasPrefix(target, prefix) {\n\t\t\treturn nil\n\t\t}\n\t}\n\n\t// If we have reached this point, the target has not matched any valid\n\t// options. Return an error that includes the target string, so it is\n\t// immediately clear what constraint failed as job specifications can","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/structs/constraint.go#L29-L65","documentation":"validateConstraintAttribute requires constraint targets using interpolation to have both opening and closing delimiters: ${...}. This error fires when the target starts with '${' but does not end with '}'. It prevents partially-formed interpolation expressions from reaching scheduler evaluation.","triggerScenarios":"A job constraint attribute like \"${node.class\" or \"${attr.network.speed\" that opens the interpolation but never closes it with '}'.","commonSituations":"Truncated lines from copy-paste; editors or templating systems stripping the closing brace; typos when hand-editing job files.","solutions":["Append the missing '}' so the attribute is a complete ${...} expression.","Verify the whole attribute string with nomad job validate before submitting.","If the value was intended as a literal (non-interpolated) name, remove the '$' prefix entirely."],"exampleFix":"// before\nconstraint {\n  attribute = \"${attr.kernel.version\"\n  operator  = \">=\"\n  value     = \"5.4\"\n}\n// after\nconstraint {\n  attribute = \"${attr.kernel.version}\"\n  operator  = \">=\"\n  value     = \"5.4\"\n}","handlingStrategy":"validation","validationCode":"if !strings.HasSuffix(strings.TrimSuffix(attr, \"}\"), \"}\") {\n  return fmt.Errorf(\"constraint attribute %q not a complete ${...} expression\", attr)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Pair every '${' with a '}' in attribute fields; editors with bracket matching help.","Avoid templating tools that may strip trailing braces; escape as needed.","Validate job specs with nomad job validate before apply."],"tags":["nomad","constraint","interpolation","validation"],"backgroundTag":"malformed-interpolation-syntax","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"}