{"record":{"id":"3d36b16d1be0e051","repo":"hashicorp/nomad","slug":"missing-metadata","errorCode":null,"errorMessage":"missing metadata","messagePattern":"missing metadata","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/encrypter.go","lineNumber":658,"sourceCode":"\n// addCipher creates a new cipherSet for the key and stores them in the keyring\nfunc (e *Encrypter) addCipher(rootKey *structs.UnwrappedRootKey) error {\n\n\tgeneratedCipher, err := e.generateCipher(rootKey)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\te.keyringLock.Lock()\n\tdefer e.keyringLock.Unlock()\n\te.keyring[rootKey.Meta.KeyID] = generatedCipher\n\treturn nil\n}\n\nfunc (e *Encrypter) generateCipher(rootKey *structs.UnwrappedRootKey) (*cipherSet, error) {\n\n\tif rootKey == nil || rootKey.Meta == nil {\n\t\treturn nil, fmt.Errorf(\"missing metadata\")\n\t}\n\tvar wrapper kms.Wrapper\n\n\tswitch rootKey.Meta.Algorithm {\n\tcase structs.EncryptionAlgorithmAES256GCM:\n\t\twrapper = aead.NewWrapper()\n\t\t_, err := wrapper.SetConfig(context.Background(),\n\t\t\taead.WithAeadType(kms.AeadTypeAesGcm),\n\t\t\taead.WithHashType(kms.HashTypeSha256),\n\t\t\taead.WithKey(rootKey.Key),\n\t\t\tkms.WithKeyId(rootKey.Meta.KeyID),\n\t\t)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"could not configure cipher: %w\", err)\n\t\t}\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"invalid algorithm %s\", rootKey.Meta.Algorithm)\n\t}","sourceCodeStart":640,"sourceCodeEnd":676,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/encrypter.go#L640-L676","documentation":"generateCipher requires a root key with populated metadata to pick the encryption algorithm and key ID. It throws \"missing metadata\" when the UnwrappedRootKey is nil or its Meta field is nil, since algorithm dispatch and key-ID tagging are impossible without it.","triggerScenarios":"addCipher is called with a root key whose Meta was never persisted, or a nil rootKey is passed (e.g. decrypt path yielded a zero-value struct).","commonSituations":"Corrupted or hand-edited raft/state key records; restoring snapshots produced by tooling that omitted the Meta block; programming errors calling generateCipher directly with an uninitialized key.","solutions":["Verify the root key record includes its KeyMetadata (KeyID, Algorithm) in state before the keyring is loaded","Rotate/re-create the affected key so a complete record with Meta is written","Restore a known-good keyring snapshot","If calling addCipher/generateCipher in tests or forks, always construct structs.UnwrappedRootKey with Meta set"],"exampleFix":"// before\nrootKey := &structs.UnwrappedRootKey{Key: keyBytes}\nerr := e.generateCipher(rootKey)\n// after\nrootKey := &structs.UnwrappedRootKey{Key: keyBytes, Meta: &structs.RootKeyMeta{KeyID: kid, Algorithm: structs.EncryptionAlgorithmAES256GCM}}\nerr := e.generateCipher(rootKey)","handlingStrategy":"validation","validationCode":"func keyHasMeta(k *structs.UnwrappedRootKey) error {\n    if k == nil || k.Meta == nil { return errors.New(\"root key missing Meta\") }\n    return nil\n}","typeGuard":"func hasMeta(k *structs.UnwrappedRootKey) bool { return k != nil && k.Meta != nil }","tryCatchPattern":"if err != nil && err.Error() == \"missing metadata\" { /* rebuild or re-rotate the key record */ }","preventionTips":["Always construct UnwrappedRootKey with Meta populated (KeyID + Algorithm)","Avoid hand-editing raft state or key records","Verify keyring integrity after snapshot restore"],"tags":["encryption","keyring","missing-metadata"],"backgroundTag":"missing-metadata","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"}