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)), nil

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Read the wrapped %v detail to identify which rule acl.NewACL rejected
  2. Fix glob patterns in the offending policy — check every pattern field for validity (e.g. 'namespace_prefix' vs plain 'namespace' usage)
  3. Re-apply the corrected policy with 'nomad acl policy apply <name> <file>'
  4. 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

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


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