hashicorp/nomad · error

attribute %q is missing a closing brace

Error message

attribute %q is missing a closing brace

What it means

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.

Source

Thrown at nomad/structs/constraint.go:47

)

// 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
		}
	}

	// If we have reached this point, the target has not matched any valid
	// options. Return an error that includes the target string, so it is
	// immediately clear what constraint failed as job specifications can

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Append the missing '}' so the attribute is a complete ${...} expression.
  2. Verify the whole attribute string with nomad job validate before submitting.
  3. If the value was intended as a literal (non-interpolated) name, remove the '$' prefix entirely.

Example fix

// before
constraint {
  attribute = "${attr.kernel.version"
  operator  = ">="
  value     = "5.4"
}
// after
constraint {
  attribute = "${attr.kernel.version}"
  operator  = ">="
  value     = "5.4"
}
Defensive patterns

Strategy: validation

Validate before calling

if !strings.HasSuffix(strings.TrimSuffix(attr, "}"), "}") {
  return fmt.Errorf("constraint attribute %q not a complete ${...} expression", attr)
}

Prevention

When it happens

Trigger: A job constraint attribute like "${node.class" or "${attr.network.speed" that opens the interpolation but never closes it with '}'.

Common situations: Truncated lines from copy-paste; editors or templating systems stripping the closing brace; typos when hand-editing job files.

Related errors


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