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

  1. Generate and set the key material on the RootKey before calling Update, e.g. args.RootKey.Key = make([]byte, 32) filled with crypto/rand.
  2. If rotating to an algorithm-default key, use the keyring Rotate endpoint instead of Update with empty material.
  3. Verify with args.RootKey.Meta.Validate() passes and len(Key) > 0 before submitting the RPC.
  4. 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

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


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/a1cfbe1e6d72480d. Report an issue: GitHub.