hashicorp/nomad · error
cannot rekey without setting the new key active
Error message
cannot rekey without setting the new key active
What it means
UpsertRootKey enforces that a rekey operation — updating an existing root key's material — must also mark that key as active. The check `rekey && !isRotation` means if the request replaces key material but does not rotate it to active, the write is rejected, since the keyring cannot have new key material applied without it becoming the active key.
Source
Thrown at nomad/state/state_store_keyring.go:38
if err != nil {
return fmt.Errorf("root key lookup failed: %v", err)
}
isRotation := false
if raw != nil {
existing := raw.(*structs.RootKey)
rootKey.CreateIndex = existing.CreateIndex
rootKey.CreateTime = existing.CreateTime
isRotation = !existing.IsActive() && rootKey.IsActive()
} else {
rootKey.CreateIndex = index
isRotation = rootKey.IsActive()
}
rootKey.ModifyIndex = index
if rekey && !isRotation {
return fmt.Errorf("cannot rekey without setting the new key active")
}
// if the upsert is for a newly-active key, we need to set all the
// other keys as inactive in the same transaction.
if isRotation {
iter, err := txn.Get(TableRootKeys, indexID)
if err != nil {
return err
}
for {
raw := iter.Next()
if raw == nil {
break
}
key := raw.(*structs.RootKey)
modified := false
switch key.State {View on GitHub (pinned to 482b49bf1a)
Solutions
- Set the key as active (Active = true) on the root key being rekeyed so the upsert is treated as a rotation.
- If the intent was only metadata update, clear the rekey flag / send a RootKeyMeta upsert instead of new key material.
- Ensure all servers run compatible Nomad versions so the keyring RPC is serialized consistently.
- Retry the keyring rotation through the standard keyring API rather than constructing state updates manually.
Example fix
// before key.Key = newKeyMaterial // rekey requested stateStore.UpsertRootKey(idx, key, true, "uuid") // key.IsActive() false -> error // after key.Key = newKeyMaterial key.Active = true // rekey implies activation stateStore.UpsertRootKey(idx, key, true, "uuid")
Defensive patterns
Strategy: validation
Validate before calling
if rekey && !key.IsActive() {
key.Active = true // rekey requires the new key be active
}
err := s.UpsertRootKey(idx, key, rekey, uuid) Type guard
func validRekeyRequest(key *structs.RootKey, rekey bool) bool {
return !rekey || key.IsActive()
} Try / catch
err := s.UpsertRootKey(idx, key, true, uuid)
if err != nil && strings.Contains(err.Error(), "cannot rekey without setting the new key active") {
key.Active = true
err = s.UpsertRootKey(idx, key, true, uuid)
} Prevention
- Treat rekey and activation as a single operation: always set Active=true when supplying new key material.
- For metadata-only changes, use RootKeyMeta upserts, never full key upserts.
- Keep server versions homogeneous so keyring RPC semantics match across the cluster.
- Test keyring rotations in a dev cluster before running them in production.
When it happens
Trigger: Calling UpsertRootKey (via applyRootKeyMetaUpsert or applyWrappedRootKeysUpsert from the keyring replication/RPC path) with a rekey flag set for an existing key whose IsActive() is false in the submitted key object.
Common situations: A keyring rotation RPC that sends new key material but omits or mangles the Active flag; leadership replication applying a wrapped-key upsert inconsistent with rotation intent; version skew between servers producing differently-shaped key metadata.
Related errors
- error parsing: root should be an object
- cannot specify Accessor ID
- network already configured but not found in state
- unable to decrypt wrapped key
- eval not found
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/a7a3109006304259.
Report an issue: GitHub.