hashicorp/nomad · error
ACL role not found
Error message
ACL role not found
What it means
deleteACLRoleByIDTxn verifies that an ACL role with the given ID exists in the acl_roles table before deleting it. If the unique index lookup returns nil, it returns "ACL role not found" instead of deleting, making the delete operation strict (no silent no-op). The error propagates out of DeleteACLRolesByID to the RPC caller.
Source
Thrown at nomad/state/state_store_acl.go:212
// Update the index table to indicate an update has occurred.
if err := txn.Insert(tableIndex, &IndexEntry{TableACLRoles, index}); err != nil {
return fmt.Errorf("index update failed: %v", err)
}
return txn.Commit()
}
// deleteACLRoleByIDTxn deletes a single ACL role from the state store using the
// provided write transaction. It is the responsibility of the caller to update
// the index table.
func (s *StateStore) deleteACLRoleByIDTxn(txn *txn, roleID string) error {
existing, err := txn.First(TableACLRoles, indexID, roleID)
if err != nil {
return fmt.Errorf("ACL role lookup failed: %v", err)
}
if existing == nil {
return errors.New("ACL role not found")
}
// Delete the existing entry from the table.
if err := txn.Delete(TableACLRoles, existing); err != nil {
return fmt.Errorf("ACL role deletion failed: %v", err)
}
return nil
}
// GetACLRoles returns an iterator that contains all ACL roles stored within
// state.
func (s *StateStore) GetACLRoles(ws memdb.WatchSet) (memdb.ResultIterator, error) {
txn := s.db.ReadTxn()
// Walk the entire table to get all ACL roles.
iter, err := txn.Get(TableACLRoles, indexID)
if err != nil {
return nil, fmt.Errorf("ACL role lookup failed: %v", err)View on GitHub (pinned to 482b49bf1a)
Solutions
- List roles (nomad acl role list) and confirm the exact ID before deleting.
- Treat this error as idempotent success in automation if the desired end state is 'role gone'.
- Re-fetch the role ID from the authoritative cluster/namespace; UUIDs are not portable across clusters.
Example fix
// before: blind delete
client.ACLRoles().Delete(roleID, nil)
// after: check existence first or tolerate not-found
_, _, err := client.ACLRoles().Get(roleID, nil)
if err == nil {
_, err = client.ACLRoles().Delete(roleID, nil)
} Defensive patterns
Strategy: validation
Validate before calling
_, _, err := client.ACLRoles().Get(roleID, nil)
if err != nil {
return fmt.Errorf("role %s does not exist, skipping delete", roleID)
} Try / catch
err := client.ACLRoles().Delete(roleID, nil)
if err != nil && strings.Contains(err.Error(), "ACL role not found") {
return nil // already deleted
} Prevention
- Fetch IDs with `nomad acl role list` rather than storing them across runs.
- Make delete scripts idempotent by ignoring not-found.
- Never reuse role IDs across clusters.
When it happens
Trigger: ACLRole.Delete RPC (nomad acl role delete <id>) with a role ID that is absent from the state store; concurrent double-delete where a second request races the first; deleting by stale ID after the role was already removed.
Common situations: Scripts re-running a deletion; deleting a role on a region/agent that never had it; stale IDs cached from a previous cluster; typo'd UUID in automation.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- ACL policy not found
- detected corrupted token within the state store: missing rol
- ACL binding rule not found
- ACL auth method not found
- service registration not found
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/b1f505afc9f3e024.
Report an issue: GitHub.