{"record":{"id":"a1cfbe1e6d72480d","repo":"hashicorp/nomad","slug":"root-key-material-is-required","errorCode":null,"errorMessage":"root key material is required","messagePattern":"root key material is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/keyring_endpoint.go","lineNumber":241,"sourceCode":"\t}\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treply.Index = index\n\treturn nil\n}\n\n// validateUpdate validates both the request and that any change to an\n// existing key is valid\nfunc (k *Keyring) validateUpdate(args *structs.KeyringUpdateRootKeyRequest) error {\n\n\terr := args.RootKey.Meta.Validate()\n\tif err != nil {\n\t\treturn err\n\t}\n\tif len(args.RootKey.Key) == 0 {\n\t\treturn fmt.Errorf(\"root key material is required\")\n\t}\n\n\t// lookup any existing key and validate the update\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.RootKey.Meta.KeyID)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif rootKey != nil && rootKey.Algorithm != args.RootKey.Meta.Algorithm {\n\t\treturn fmt.Errorf(\"root key algorithm cannot be changed after a key is created\")\n\t}\n\n\treturn nil\n}","sourceCodeStart":223,"sourceCodeEnd":259,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/keyring_endpoint.go#L223-L259","documentation":"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.","triggerScenarios":"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.","commonSituations":"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'.","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."],"exampleFix":"// before\nrk := &structs.RootKeyMeta{KeyID: id, Algorithm: structs.EncryptionAlgorithmAES256GCM}\n_, err := client.Keyring().Update(&structs.KeyringUpdateRootKeyRequest{RootKey: &structs.RootKey{Meta: rk}})\n// after\nkey := make([]byte, 32)\nif _, err := rand.Read(key); err != nil { return err }\n_, err := client.Keyring().Update(&structs.KeyringUpdateRootKeyRequest{RootKey: &structs.RootKey{Meta: rk, Key: key}})","handlingStrategy":"validation","validationCode":"if req.RootKey == nil || len(req.RootKey.Key) == 0 {\n    return fmt.Errorf(\"root key material must be generated before Update\")\n}","typeGuard":"func hasKeyMaterial(rk *structs.RootKey) bool {\n    return rk != nil && rk.Meta != nil && len(rk.Key) > 0\n}","tryCatchPattern":null,"preventionTips":["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."],"tags":["nomad","keyring","validation","root-key"],"backgroundTag":"missing-required-argument","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"}