hashicorp/nomad · error
invalid acl policy: %v
Error message
invalid acl policy: %v
What it means
This error is produced by hclDecode in acl/policy.go, which wraps hcl.Decode in a recover() handler. When the HCL decoder panics while parsing ACL policy rules, the panic value is converted into "invalid acl policy: %v". It propagates up through NewACL (including construction of the package-level ManagementACL in acl/acl.go init).
Source
Thrown at acl/policy.go:736
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)
}
if p.Plugin != nil && !p.Plugin.isValid() {
return nil, fmt.Errorf("Invalid plugin policy: %#v", p.Plugin)
}
return p, nil
}
// hclDecode wraps hcl.Decode function but handles any unexpected panics
func hclDecode(p *Policy, rules string) (err error) {
defer func() {
if rerr := recover(); rerr != nil {
err = fmt.Errorf("invalid acl policy: %v", rerr)
}
}()
if err = hcl.Decode(p, rules); err != nil {
return err
}
// Manually parse the policy to fix blocks without labels.
//
// Due to a bug in the way HCL decodes files, a block without a label may
// return an incorrect key value and make it impossible to determine if the
// key was set by the user or incorrectly set by the decoder.
//
// By manually parsing the file we are able to determine if the label is
// missing in the file and set them to an empty string so the policy
// validation can return the appropriate errors.
root, err := hcl.Parse(rules)
if err != nil {View on GitHub (pinned to 482b49bf1a)
Solutions
- Inspect the panic message appended after 'invalid acl policy:' to locate the malformed input.
- Validate the policy rules as well-formed HCL before passing them to NewACL.
- If triggered inside Consul startup (init of ManagementACL), verify the installed consul/acl package version and upgrade, since ManagementACL uses nil rules and panics here indicate a library bug.
Example fix
// before
acl, err := acl.NewACL(false, []byte(garbageRules))
// after
if !hclutil.ValidRules(rules) { return fmt.Errorf("rejecting malformed policy input") }
acl, err := acl.NewACL(false, rules) Defensive patterns
Strategy: try-catch
Validate before calling
// sanity-check input is plausibly HCL before NewACL
if len(rules) == 0 || (!strings.Contains(string(rules), "key_prefix") && !strings.Contains(string(rules), "service") && !strings.Contains(string(rules), "node")) {
return fmt.Errorf("input does not look like ACL policy HCL")
} Try / catch
// NewACL already recovers panics into this error
p, err := acl.NewACL(isManagement, rules)
if err != nil {
if strings.HasPrefix(err.Error(), "invalid acl policy:") {
return fmt.Errorf("policy input rejected: %w", err)
}
return err
} Prevention
- Never feed raw, untrusted bytes directly into NewACL.
- Validate HCL syntax upstream with hcl.Parse before constructing ACLs.
- Pin your consul/acl library version and watch for decoder panic fixes.
When it happens
Trigger: Calling NewACL (or TestACL variants) with rules that make the HCL parser panic — deeply malformed or structurally invalid policy input that hcl.Decode cannot handle gracefully.
Common situations: Corrupted or truncated ACL policy definitions; binary garbage or non-HCL content passed as rules; a regression where policies built programmatically trigger a library panic.
Related errors
- Invalid quota policy: %#v
- Invalid plugin policy: %#v
- failed to parse policy: %w
- panic(err)
- no one-time token returned
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/2d6a18c0b0814513.
Report an issue: GitHub.