hashicorp/nomad · critical

panic(err)

Error message

panic(err)

What it means

NewClientACL constructs a permissive client ACL (wildcard pool, write access for client, read for agent/server) by delegating to NewACL(false, []*Policy{}). If NewACL returns an error even for this empty-policy configuration, the constructor calls panic(err), turning an ACL initialization failure into a process crash rather than a returnable error.

Source

Thrown at acl/virtual.go:17

// Copyright IBM Corp. 2015, 2026
// SPDX-License-Identifier: BUSL-1.1

package acl

var ClientACL = initClientACL()
var ServerACL = initServerACL()
var ACLsDisabledACL = initACLsDisabledACL()

func initClientACL() *ACL {
	return NewClientACL("*")
}

func NewClientACL(pool string) *ACL {
	aclObj, err := NewACL(false, []*Policy{})
	if err != nil {
		panic(err)
	}
	aclObj.client = PolicyWrite
	aclObj.pool = pool
	aclObj.agent = PolicyRead
	aclObj.server = PolicyRead
	return aclObj
}

func initServerACL() *ACL {
	aclObj, err := NewACL(false, []*Policy{})
	if err != nil {
		panic(err)
	}
	aclObj.agent = PolicyRead
	aclObj.server = PolicyWrite
	return aclObj
}

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Fix the underlying NewACL failure: inspect the wrapped error to find why empty-policy ACL creation failed (usually subsystem initialization ordering).
  2. Ensure the ACL subsystem/store is initialized before any code path (init functions, identity resolvers) constructs client ACLs.
  3. In library code, replace panic with returning an error or a cached singleton so a single init failure does not crash the process.
  4. In tests, initialize the ACL manager/fixtures before calling NewClientACL or use the AllowAll helper after subsystem setup.

Example fix

// before
// aclObj, err := NewACL(false, []*Policy{})
// if err != nil { panic(err) }

// after (caller-side guard)
// defer func() {
// 	if r := recover(); r != nil {
// 		log.Errorf("NewClientACL panicked: %v", r)
// 	}
// }()
// acl := NewClientACL("*")
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure ACL subsystem is initialized before calling
if !aclSubsystemReady() {
	return errors.New("ACL subsystem not initialized; cannot build client ACL")
}

Type guard

func safeNewClientACL(pool string) (acl *ACL, err error) {
	defer func() {
		if r := recover(); r != nil {
			err = fmt.Errorf("NewClientACL panicked: %v", r)
		}
	}()
	return NewClientACL(pool), nil
}

Try / catch

acl, err := safeNewClientACL("*")
if err != nil {
	log.Errorf("client ACL init failed: %v", err)
	return nil, err // degrade instead of crashing
}

Prevention

When it happens

Trigger: Calling NewClientACL (directly, via the AllowAll-style wrapper, initClientACL, or during ResolveClientIdentityACL/resolveClaims identity resolution) when NewACL(false, []*Policy{}) fails — practically only when the underlying ACL management/initialization machinery is unavailable or in a degraded state.

Common situations: ACL backend/state store not initialized before building client ACLs; test harnesses constructing ACLs before the ACL subsystem is ready; regressions in NewACL that make even empty-policy construction fail.

Related errors


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