hashicorp/nomad · error
root key material is required
Error message
root key material is required
What it means
The Nomad keyring Update endpoint rejects an update request whose RootKey entry carries no key material. Root key rotation/upsert requires the actual key bytes so the keyring can store an encryptable key; an empty Key field is treated as an invalid request and rejected before any Raft write.
Source
Thrown at nomad/keyring_endpoint.go:241
}
if err != nil {
return err
}
reply.Index = index
return nil
}
// validateUpdate validates both the request and that any change to an
// existing key is valid
func (k *Keyring) validateUpdate(args *structs.KeyringUpdateRootKeyRequest) error {
err := args.RootKey.Meta.Validate()
if err != nil {
return err
}
if len(args.RootKey.Key) == 0 {
return fmt.Errorf("root key material is required")
}
// lookup any existing key and validate the update
snap, err := k.srv.fsm.State().Snapshot()
if err != nil {
return err
}
ws := memdb.NewWatchSet()
rootKey, err := snap.RootKeyByID(ws, args.RootKey.Meta.KeyID)
if err != nil {
return err
}
if rootKey != nil && rootKey.Algorithm != args.RootKey.Meta.Algorithm {
return fmt.Errorf("root key algorithm cannot be changed after a key is created")
}
return nil
}View on GitHub (pinned to 482b49bf1a)
Solutions
- Generate and set the key material on the RootKey before calling Update, e.g. args.RootKey.Key = make([]byte, 32) filled with crypto/rand.
- If rotating to an algorithm-default key, use the keyring Rotate endpoint instead of Update with empty material.
- Verify with args.RootKey.Meta.Validate() passes and len(Key) > 0 before submitting the RPC.
- Check that the client-side key generation step (file read, KMS fetch, random bytes) actually succeeded and wasn't silently swallowed.
Example fix
// before
rk := &structs.RootKeyMeta{KeyID: id, Algorithm: structs.EncryptionAlgorithmAES256GCM}
_, err := client.Keyring().Update(&structs.KeyringUpdateRootKeyRequest{RootKey: &structs.RootKey{Meta: rk}})
// after
key := make([]byte, 32)
if _, err := rand.Read(key); err != nil { return err }
_, err := client.Keyring().Update(&structs.KeyringUpdateRootKeyRequest{RootKey: &structs.RootKey{Meta: rk, Key: key}}) Defensive patterns
Strategy: validation
Validate before calling
if req.RootKey == nil || len(req.RootKey.Key) == 0 {
return fmt.Errorf("root key material must be generated before Update")
} Type guard
func hasKeyMaterial(rk *structs.RootKey) bool {
return rk != nil && rk.Meta != nil && len(rk.Key) > 0
} Prevention
- Always fill RootKey.Key with crypto/rand bytes (or a fetched KMS key) before calling Update.
- Use the Rotate endpoint for algorithm-driven rotation instead of hand-building Update requests.
- Validate requests with RootKeyMeta.Validate() plus a length check before RPC.
- Log (not the key bytes) whether key generation succeeded in rotation scripts.
When it happens
Trigger: Calling the Keyring.Update RPC (or `nomad keyrotor key update` / keyring API PUT) with args.RootKey.Key empty or a zero-length byte slice, e.g. submitting a key spec with only KeyID/Algorithm/Meta set.
Common situations: Scripting key rotation and forgetting to generate/attach the key bytes; a template or CI step that leaves the key field blank; marshalling a key from a file that failed to read; copying an existing key object and clearing Key to 'avoid sending secrets'.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- root key algorithm is required
- root key algorithm cannot be changed after a key is created
- root key ID is required
- active root key cannot be deleted - call rotate first
- unknown keyring provider: %q
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/a1cfbe1e6d72480d.
Report an issue: GitHub.