{"record":{"id":"f4f84ebba9fd3a24","repo":"hashicorp/nomad","slug":"active-root-key-cannot-be-deleted-call-rotate-fi","errorCode":null,"errorMessage":"active root key cannot be deleted - call rotate first","messagePattern":"active root key cannot be deleted - call rotate first","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/keyring_endpoint.go","lineNumber":355,"sourceCode":"\n\t// lookup any existing key and validate the delete\n\tvar index uint64\n\tsnap, err := k.srv.fsm.State().Snapshot()\n\tif err != nil {\n\t\treturn err\n\t}\n\tws := memdb.NewWatchSet()\n\trootKey, err := snap.RootKeyByID(ws, args.KeyID)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif rootKey == nil {\n\t\treturn errors.New(\"root key not found\")\n\t}\n\n\tif rootKey != nil && rootKey.IsActive() {\n\t\treturn fmt.Errorf(\"active root key cannot be deleted - call rotate first\")\n\t}\n\n\t// make sure the key was used to encrypt an existing variable\n\trootKeyInUse, err := snap.IsRootKeyInUse(args.KeyID)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif rootKeyInUse && !args.Force {\n\t\treturn errors.New(\"root key in use, cannot delete\")\n\t}\n\n\t_, index, err = k.srv.raftApply(structs.WrappedRootKeysDeleteRequestType, args)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// remove the key from the keyring too\n\tk.encrypter.RemoveKey(args.KeyID)","sourceCodeStart":337,"sourceCodeEnd":373,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/keyring_endpoint.go#L337-L373","documentation":"Nomad forbids deleting the keyring's currently active root key. The active key encrypts new variables; removing it would break encryption and future decryption workflows. The operator must rotate leadership to install a new active key first.","triggerScenarios":"Calling Keyring.Delete with the KeyID of the key for which rootKey.IsActive() is true — i.e. the key currently marked as the encryption key in state store.","commonSituations":"Cleanup scripts trying to prune keys and selecting the newest (active) key; operators wanting to 'remove and replace' a compromised key directly instead of rotating; misunderstanding of key states (active vs deprecated/unused).","solutions":["Rotate the keyring first (Rotate RPC / `nomad keyrotor key rotate`) so a new key becomes active, then delete the old key.","Choose a non-active, unused key ID to delete; check state via Get/list before deleting.","If the key is active but must be replaced, perform rotate → wait for replication → delete the now-deprecated key."],"exampleFix":"// before\nclient.Keyring().Delete(&structs.KeyringDeleteRootKeyRequest{KeyID: activeKeyID})\n// after\nclient.Keyring().Rotate(&structs.KeyringRotateRootKeyRequest{})\nclient.Keyring().Delete(&structs.KeyringDeleteRootKeyRequest{KeyID: oldKeyID})","handlingStrategy":"validation","validationCode":"key, _, err := client.Keyring().Get(&structs.KeyringGetRootKeyRequest{KeyID: id}, nil)\nif err == nil && key != nil && key.Meta.IsActive() {\n    return fmt.Errorf(\"key %s is active; rotate before deleting\", id)\n}","typeGuard":"func isDeletableKey(k *structs.RootKey) bool {\n    return k != nil && !k.Meta.IsActive()\n}","tryCatchPattern":"err := deleteKey(id)\nif err != nil && strings.Contains(err.Error(), \"active root key cannot be deleted\") {\n    if rErr := client.Keyring().Rotate(&structs.KeyringRotateRootKeyRequest{}, nil); rErr == nil {\n        return deleteKey(id) // retry after rotation\n    }\n}\nreturn err","preventionTips":["Always Get the key and check IsActive() before delete.","Adopt the rotate-then-delete pattern for key replacement.","Restrict keyring-delete ACLs to controlled cleanup tooling.","Verify the key is not in use (IsRootKeyInUse) to avoid the follow-on in-use error."],"tags":["nomad","keyring","root-key","state-constraint"],"backgroundTag":"key-in-use-cannot-be-deleted","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"}