hashicorp/nomad · error
Invalid sentinel policy: %#v
Error message
Invalid sentinel policy: %#v
What it means
acl.Parse (acl/policy.go:706) validates the top-level sentinel block's Policy string with isPolicyValid, which only accepts deny, read, write, scale. A non-empty sentinel policy with any other value fails parsing and rejects the whole policy. Sentinel blocks are Nomad Enterprise features, so this typically surfaces in enterprise policy files.
Solutions
- Set policy to one of exactly: deny, read, write, scale (lowercase).
- For granular Sentinel permissions, use capabilities = ["sentinel-read", "sentinel-submit", "sentinel-delete"] instead of the shorthand.
- Check the %#v struct in the error to identify the offending value.
Example fix
// before
sentinel {
policy = "submit"
}
// after
sentinel {
capabilities = ["sentinel-submit"]
} Defensive patterns
Strategy: validation
Validate before calling
if policy.Sentinel != nil && policy.Sentinel.Policy != "" &&
!map[string]bool{"deny": true, "read": true, "write": true, "scale": true}[policy.Sentinel.Policy] {
return fmt.Errorf("sentinel policy %q must be deny|read|write|scale", policy.Sentinel.Policy)
} Type guard
func isPolicyValid(policy string) bool {
switch policy {
case "deny", "read", "write", "scale":
return true
}
return false
} Try / catch
_, err := acl.Parse(rules, acl.PolicyParseStrict)
if err != nil {
if strings.Contains(err.Error(), "Invalid sentinel policy") {
// replace the sentinel shorthand policy or switch to capabilities
}
return err
} Prevention
- Use only deny, read, write, scale in the sentinel policy field
- Use capabilities = ["sentinel-..."] for submit/delete grants instead of the policy shorthand
- Note sentinel blocks require Nomad Enterprise — validate the target edition supports them
When it happens
Trigger: acl.Parse on a policy containing sentinel { policy = "<invalid>" } where the value is not exactly "deny", "read", "write", or "scale" — e.g. 'submit', 'sentinel-read', or an empty string set by a template.
Common situations: Putting sentinel capability names (sentinel-submit, sentinel-delete) into the policy field instead of the capabilities list; case mistakes; OSS Nomad users pasting an enterprise example policy verbatim with modified values.
Related errors
- Invalid sentinel capability
- Invalid agent policy: %#v
- Invalid host volume name: %#v
- Invalid host volume policy: %#v
- Invalid missing variable path in namespace
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/25e24621da2dde0b.
Report an issue: GitHub.
Appendix: source
Thrown at acl/policy.go:706
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)
}
}
// Expand the short hand policy to the capabilities and
// add to any existing capabilities
if p.Sentinel.Policy != "" {
extraCap := expandSentinelPolicy(p.Sentinel.Policy)
p.Sentinel.Capabilities = append(p.Sentinel.Capabilities, extraCap...)
}
}
if p.Quota != nil && !isPolicyValid(p.Quota.Policy) {
return nil, fmt.Errorf("Invalid quota policy: %#v", p.Quota)
}View on GitHub (pinned to 482b49bf1a)