hashicorp/nomad · error
active root key cannot be deleted - call rotate first
Error message
active root key cannot be deleted - call rotate first
What it means
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.
Source
Thrown at nomad/keyring_endpoint.go:355
// lookup any existing key and validate the delete
var index uint64
snap, err := k.srv.fsm.State().Snapshot()
if err != nil {
return err
}
ws := memdb.NewWatchSet()
rootKey, err := snap.RootKeyByID(ws, args.KeyID)
if err != nil {
return err
}
if rootKey == nil {
return errors.New("root key not found")
}
if rootKey != nil && rootKey.IsActive() {
return fmt.Errorf("active root key cannot be deleted - call rotate first")
}
// make sure the key was used to encrypt an existing variable
rootKeyInUse, err := snap.IsRootKeyInUse(args.KeyID)
if err != nil {
return err
}
if rootKeyInUse && !args.Force {
return errors.New("root key in use, cannot delete")
}
_, index, err = k.srv.raftApply(structs.WrappedRootKeysDeleteRequestType, args)
if err != nil {
return err
}
// remove the key from the keyring too
k.encrypter.RemoveKey(args.KeyID)View on GitHub (pinned to 482b49bf1a)
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.
Example fix
// before
client.Keyring().Delete(&structs.KeyringDeleteRootKeyRequest{KeyID: activeKeyID})
// after
client.Keyring().Rotate(&structs.KeyringRotateRootKeyRequest{})
client.Keyring().Delete(&structs.KeyringDeleteRootKeyRequest{KeyID: oldKeyID}) Defensive patterns
Strategy: validation
Validate before calling
key, _, err := client.Keyring().Get(&structs.KeyringGetRootKeyRequest{KeyID: id}, nil)
if err == nil && key != nil && key.Meta.IsActive() {
return fmt.Errorf("key %s is active; rotate before deleting", id)
} Type guard
func isDeletableKey(k *structs.RootKey) bool {
return k != nil && !k.Meta.IsActive()
} Try / catch
err := deleteKey(id)
if err != nil && strings.Contains(err.Error(), "active root key cannot be deleted") {
if rErr := client.Keyring().Rotate(&structs.KeyringRotateRootKeyRequest{}, nil); rErr == nil {
return deleteKey(id) // retry after rotation
}
}
return err Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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).
Related errors
- root key material is required
- root key algorithm cannot be changed after a key is created
- root key metadata is required
- root key UUID is required
- root key algorithm is required
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/f4f84ebba9fd3a24.
Report an issue: GitHub.