hashicorp/nomad · error

Invalid operator capability '%s'

Error message

Invalid operator capability '%s'

What it means

acl.Parse (acl/policy.go:692) checks each entry of the operator block's Capabilities list with isOperatorCapabilityValid, which only accepts deny, snapshot-save, keyring-rotate, keyring-read, keyring-delete, and license-read. Any other capability string fails parsing and rejects the whole policy.

Source

Thrown at acl/policy.go:692

	}

	p.ExtraKeysHCL = nil

	if p.Agent != nil && !isPolicyValid(p.Agent.Policy) {
		return nil, fmt.Errorf("Invalid agent policy: %#v", p.Agent)
	}

	if p.Node != nil && !isPolicyValid(p.Node.Policy) {
		return nil, fmt.Errorf("Invalid node policy: %#v", p.Node)
	}

	if p.Operator != nil {
		if p.Operator.Policy != "" && !isPolicyValid(p.Operator.Policy) {
			return nil, fmt.Errorf("Invalid operator policy: %#v", p.Operator)
		}
		for _, cap := range p.Operator.Capabilities {
			if !isOperatorCapabilityValid(cap) {
				return nil, fmt.Errorf("Invalid operator capability '%s'", cap)
			}
		}

		// Expand the short hand policy to the capabilities and
		// add to any existing capabilities
		if p.Operator.Policy != "" {
			extraCap := expandOperatorPolicy(p.Operator.Policy)
			p.Operator.Capabilities = append(p.Operator.Capabilities, extraCap...)
		}
	}

	if p.Sentinel != nil {
		if p.Sentinel.Policy != "" && !isPolicyValid(p.Sentinel.Policy) {
			return nil, fmt.Errorf("Invalid sentinel policy: %#v", p.Sentinel)
		}
		for _, cap := range p.Sentinel.Capabilities {
			if !isSentinelCapabilityValid(cap) {
				return nil, fmt.Errorf("Invalid sentinel capability '%s'", cap)

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Replace the invalid capability with one of exactly: deny, snapshot-save, keyring-rotate, keyring-read, keyring-delete, license-read.
  2. Alternatively remove capabilities and use shorthand policy = "read"|"write"|"deny".
  3. The '%s' in the error names the exact rejected capability — fix that entry.

Example fix

// before
operator {
  capabilities = ["snapshot"]
}
// after
operator {
  capabilities = ["snapshot-save"]
}
Defensive patterns

Strategy: validation

Validate before calling

var validOperatorCaps = map[string]bool{"deny": true, "snapshot-save": true, "keyring-rotate": true,
    "keyring-read": true, "keyring-delete": true, "license-read": true}
if policy.Operator != nil {
    for _, c := range policy.Operator.Capabilities {
        if !validOperatorCaps[c] {
            return fmt.Errorf("invalid operator capability %q", c)
        }
    }
}

Type guard

func isOperatorCapabilityValid(cap string) bool {
    switch cap {
    case "deny", "snapshot-save", "keyring-rotate", "keyring-read", "keyring-delete", "license-read":
        return true
    }
    return false
}

Try / catch

_, err := acl.Parse(rules, acl.PolicyParseStrict)
if err != nil {
    if strings.Contains(err.Error(), "Invalid operator capability") {
        // fix the quoted capability name in the operator block
    }
    return err
}

Prevention

When it happens

Trigger: acl.Parse on a policy where operator { capabilities = [...] } contains an unrecognized string such as 'snapshot', 'license-manager', or a namespace capability like 'submit-job'.

Common situations: Typos or shortened forms of capability names ('snapshot' vs 'snapshot-save'); version drift — 'license-read' only exists in Nomad Enterprise/newer versions, so policies generated elsewhere may carry unsupported entries; confusing operator capabilities with node-pool or sentinel capabilities.

Related errors


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