hashicorp/nomad · error

attribute %q is missing an opening brace

Error message

attribute %q is missing an opening brace

What it means

This error comes from Nomad's constraint attribute validation (validateConstraintAttribute). Constraint targets can be an attribute path or an interpolation expression. If a target starts with '$' but is not exactly '${...}', the opening brace is missing, so the constraint is rejected. It exists to catch malformed interpolation syntax early at job validation time.

Source

Thrown at nomad/structs/constraint.go:44

		"${device.",
		"${meta.",
	}
)

// validateConstraintAttribute ensures the constraint attribute is valid. It
// does this by ensuring any interpolated field can be handled by the
// resolveTarget function.
func validateConstraintAttribute(target string) error {

	// If no prefix delimieter is included, we assume this is a literal value
	// and is therefore valid.
	if !strings.HasPrefix(target, "$") {
		return nil
	}

	// Must have the correct opening and closing delimeters.
	if !strings.HasPrefix(target, "${") {
		return fmt.Errorf("attribute %q is missing an opening brace", target)
	}
	if !strings.HasSuffix(target, "}") {
		return fmt.Errorf("attribute %q is missing a closing brace", target)
	}

	// Perform our exact target matching first. If the target does not hit this
	// exact match, we will fall through to the prefix match check.
	if slices.Contains(validConstraintExactTargets, target) {
		return nil
	}

	// Check the target against our valid prefixes.
	for _, prefix := range validConstraintPrefixTargets {
		if strings.HasPrefix(target, prefix) {
			return nil
		}
	}

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Wrap the variable name in braces: change "$node.class" to "${node.class}".
  2. If you meant an exact target, use one of the valid literal targets (e.g. "${node.unique.id}") with full ${...} syntax.
  3. Run nomad job validate locally to catch the malformed attribute before submitting.

Example fix

// before
constraint {
  attribute = "$node.class"
  operator  = "="
  value     = "linux"
}
// after
constraint {
  attribute = "${node.class}"
  operator  = "="
  value     = "linux"
}
Defensive patterns

Strategy: validation

Validate before calling

func validConstraintTarget(target string) bool {
  if !strings.HasPrefix(target, "$") { return true }
  return strings.HasPrefix(target, "${") && strings.HasSuffix(target, "}")
}

Prevention

When it happens

Trigger: Registering or validating a job whose constraint 'attribute' field starts with '$' but not '${', e.g. attribute="$node.class" or attribute="$attr" instead of "${node.class}" / "${attr...}".

Common situations: Hand-written job specs where the author forgot the opening brace after '$'; typos when converting from older HCL interpolation styles; copy-paste errors dropping '{'.

Related errors


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