{"record":{"id":"b1f505afc9f3e024","repo":"hashicorp/nomad","slug":"acl-role-not-found","errorCode":null,"errorMessage":"ACL role not found","messagePattern":"ACL role not found","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/state/state_store_acl.go","lineNumber":212,"sourceCode":"\t// Update the index table to indicate an update has occurred.\n\tif err := txn.Insert(tableIndex, &IndexEntry{TableACLRoles, index}); err != nil {\n\t\treturn fmt.Errorf(\"index update failed: %v\", err)\n\t}\n\n\treturn txn.Commit()\n}\n\n// deleteACLRoleByIDTxn deletes a single ACL role from the state store using the\n// provided write transaction. It is the responsibility of the caller to update\n// the index table.\nfunc (s *StateStore) deleteACLRoleByIDTxn(txn *txn, roleID string) error {\n\n\texisting, err := txn.First(TableACLRoles, indexID, roleID)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"ACL role lookup failed: %v\", err)\n\t}\n\tif existing == nil {\n\t\treturn errors.New(\"ACL role not found\")\n\t}\n\n\t// Delete the existing entry from the table.\n\tif err := txn.Delete(TableACLRoles, existing); err != nil {\n\t\treturn fmt.Errorf(\"ACL role deletion failed: %v\", err)\n\t}\n\treturn nil\n}\n\n// GetACLRoles returns an iterator that contains all ACL roles stored within\n// state.\nfunc (s *StateStore) GetACLRoles(ws memdb.WatchSet) (memdb.ResultIterator, error) {\n\ttxn := s.db.ReadTxn()\n\n\t// Walk the entire table to get all ACL roles.\n\titer, err := txn.Get(TableACLRoles, indexID)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"ACL role lookup failed: %v\", err)","sourceCodeStart":194,"sourceCodeEnd":230,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/state/state_store_acl.go#L194-L230","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: blind delete\nclient.ACLRoles().Delete(roleID, nil)\n// after: check existence first or tolerate not-found\n_, _, err := client.ACLRoles().Get(roleID, nil)\nif err == nil {\n    _, err = client.ACLRoles().Delete(roleID, nil)\n}","handlingStrategy":"validation","validationCode":"_, _, err := client.ACLRoles().Get(roleID, nil)\nif err != nil {\n    return fmt.Errorf(\"role %s does not exist, skipping delete\", roleID)\n}","typeGuard":null,"tryCatchPattern":"err := client.ACLRoles().Delete(roleID, nil)\nif err != nil && strings.Contains(err.Error(), \"ACL role not found\") {\n    return nil // already deleted\n}","preventionTips":["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."],"tags":["nomad","acl","state-store","delete-not-found"],"backgroundTag":"resource-not-found","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}