hashicorp/nomad · error

selector is invalid: %v

Error message

selector is invalid: %v

What it means

When an ACL binding rule declares a Selector, Nomad compiles it with go-bexpr at validation time; if bexpr.CreateEvaluator cannot parse the expression, the rule would ambiguously fail at login, so validation wraps the parse error as "selector is invalid". The wrapped %v contains the exact bexpr syntax problem.

Source

Thrown at nomad/structs/acl.go:2116

		mErr.Errors = append(mErr.Errors, errors.New("bind type is missing"))
	case ACLBindingRuleBindTypeRole, ACLBindingRuleBindTypePolicy:
		if a.BindName == "" {
			mErr.Errors = append(mErr.Errors, errors.New("bind name is missing"))
		}
	case ACLBindingRuleBindTypeManagement:
		if a.BindName != "" {
			mErr.Errors = append(mErr.Errors, errors.New("bind name should be empty"))
		}
	default:
		mErr.Errors = append(mErr.Errors, fmt.Errorf("unsupported bind type: %q", a.BindType))
	}

	// If there is a selector configured, ensure that go-bexpr can parse this.
	// Otherwise, the user will get an ambiguous failure when attempting to
	// login.
	if a.Selector != "" {
		if _, err := bexpr.CreateEvaluator(a.Selector, nil); err != nil {
			mErr.Errors = append(mErr.Errors, fmt.Errorf("selector is invalid: %v", err))
		}
	}

	return mErr.ErrorOrNil()
}

// Merge merges binding rule a with b. It sets all required empty fields of rule
// a to corresponding values of rule b, except for "ID" which must be provided.
func (a *ACLBindingRule) Merge(b *ACLBindingRule) {
	a.BindName = helper.Merge(a.BindName, b.BindName)
	a.BindType = helper.Merge(a.BindType, b.BindType)
	a.AuthMethod = helper.Merge(a.AuthMethod, b.AuthMethod)
}

// SetHash is used to compute and set the hash of the ACL binding rule. This
// should be called every and each time a user specified field on the method is
// changed before updating the Nomad state store.
func (a *ACLBindingRule) SetHash() []byte {

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Read the wrapped bexpr error to locate the offending token/position and fix the expression syntax.
  2. Test the selector with go-bexpr or a minimal Nomad API call before submitting.
  3. Simplify the expression (split into multiple rules) if it is complex.
  4. Ensure string values are properly quoted and parentheses balanced.

Example fix

// before
selector = " ENG in list(value.roles) "

// after
selector = """"eng" in list(value.roles)"""
Defensive patterns

Strategy: validation

Validate before calling

if rule.Selector != "" {
    if _, err := bexpr.CreateEvaluator(rule.Selector, nil); err != nil {
        return fmt.Errorf("selector syntax invalid: %w", err)
    }
}

Try / catch

if err := client.ACLBindingRules().Upsert(rule); err != nil && strings.Contains(err.Error(), "selector is invalid") {
    // parse out the nested bexpr error and re-prompt the operator to fix the expression
    return fmt.Errorf("fix binding rule selector: %w", err)
}

Prevention

When it happens

Trigger: Creating/updating a binding rule with a Selector expression that go-bexpr cannot parse - unbalanced parentheses, invalid operators, unknown comparison syntax, or referencing fields with malformed identifiers.

Common situations: Hand-written boolean selectors with syntax mistakes; using quote/escaping incorrectly around values; migrating selectors from other systems with different expression languages; testing selectors that work in one IdP claim shape but are syntactically invalid.

Related errors


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