hashicorp/nomad · error
failed to construct ACL: %v
Error message
failed to construct ACL: %v
What it means
CompileACLObject returns this when the parsed policies are individually valid HCL but acl.NewACL fails to build the combined ACL object — typically semantically invalid rule contents (e.g. bad glob patterns or deny/read conflicts the ACL constructor rejects). The token cannot be authorized until resolved.
Source
Thrown at nomad/structs/funcs.go:446
entry, ok := cache.Get(cacheKey)
if ok {
return entry.Get(), nil
}
// Parse the policies
parsed := make([]*acl.Policy, 0, len(policies))
for _, policy := range policies {
p, err := acl.Parse(policy.Rules, acl.PolicyParseLenient)
if err != nil {
return nil, fmt.Errorf("failed to parse %q: %v", policy.Name, err)
}
parsed = append(parsed, p)
}
// Create the ACL object
aclObj, err := acl.NewACL(false, parsed)
if err != nil {
return nil, fmt.Errorf("failed to construct ACL: %v", err)
}
// Update the cache
cache.Add(cacheKey, aclObj)
return aclObj, nil
}
// GenerateMigrateToken will create a token for a client to access an
// authenticated volume of another client to migrate data for sticky volumes.
func GenerateMigrateToken(allocID, nodeSecretID string) (string, error) {
h, err := blake2b.New512([]byte(nodeSecretID))
if err != nil {
return "", err
}
_, _ = h.Write([]byte(allocID))
return base64.URLEncoding.EncodeToString(h.Sum(nil)), nilView on GitHub (pinned to 482b49bf1a)
Solutions
- Read the wrapped %v detail to identify which rule acl.NewACL rejected
- Fix glob patterns in the offending policy — check every pattern field for validity (e.g. 'namespace_prefix' vs plain 'namespace' usage)
- Re-apply the corrected policy with 'nomad acl policy apply <name> <file>'
- Narrow down by temporarily attaching only the suspect policy to a test token and compiling
Example fix
// before
key_prefix "" { policy = "write"; deny = true }
// after
key_prefix "" { policy = "deny" } Defensive patterns
Strategy: validation
Validate before calling
// go: parse and construct locally before compiling the full set
parsed := make([]*acl.Policy, 0, len(policies))
for _, p := range policies {
pp, err := acl.Parse(p.Rules, acl.PolicyParseLenient)
if err != nil { return fmt.Errorf("policy %q unparseable", p.Name) }
parsed = append(parsed, pp)
}
if _, err := acl.NewACL(false, parsed); err != nil {
return fmt.Errorf("policies cannot combine into a valid ACL: %v", err)
} Try / catch
aclObj, err := structs.CompileACLObject(cache, policies)
if err != nil {
if strings.HasPrefix(err.Error(), "failed to construct ACL") {
// invalid rule semantics: review globs and deny rules
}
return err
} Prevention
- Avoid invalid glob patterns in policy fields
- Don't mix policy="deny" with policy="write" on overlapping prefixes; use policy="deny" directly
- Review every attached policy when a token suddenly fails authorization
When it happens
Trigger: resolveTokenAndACL / resolveClaims / resolveACLFromToken call CompileACLObject and acl.NewACL(false, parsed) errors while combining the token's policies and any management/default policies.
Common situations: A policy containing invalid wildcard/glob patterns (e.g. over-broad '*' usage in disallowed fields) or inconsistent rule sets introduced by an edit; policies written by automation with corrupted rules.
Related errors
- ACL policy not found
- ACL role not found
- detected corrupted token within the state store: missing rol
- ACL binding rule not found
- ACL auth method not found
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/5bd9e5e08ab1bd45.
Report an issue: GitHub.