{"record":{"id":"62ca0f75937812a2","repo":"getsops/sops","slug":"failed-to-decrypt-sops-data-key-from-vault-transit","errorCode":null,"errorMessage":"failed to decrypt sops data key from Vault transit backend '%s': %w","messagePattern":"failed to decrypt sops data key from Vault transit backend '(.+?)': %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"hcvault/keysource.go","lineNumber":292,"sourceCode":"// Consider using DecryptContext instead.\nfunc (key *MasterKey) Decrypt() ([]byte, error) {\n\treturn key.DecryptContext(context.Background())\n}\n\n// DecryptContext decrypts the EncryptedKey field with Vault Transit and returns the result.\nfunc (key *MasterKey) DecryptContext(ctx context.Context) ([]byte, error) {\n\tfullPath := key.decryptPath()\n\n\tclient, err := vaultClient(key.VaultAddress, key.token, key.httpClient)\n\tif err != nil {\n\t\tlog.WithField(\"Path\", fullPath).Info(\"Decryption failed\")\n\t\treturn nil, err\n\t}\n\n\tsecret, err := client.Logical().WriteWithContext(ctx, fullPath, decryptPayload(key.EncryptedKey))\n\tif err != nil {\n\t\tlog.WithField(\"Path\", fullPath).Info(\"Decryption failed\")\n\t\treturn nil, fmt.Errorf(\"failed to decrypt sops data key from Vault transit backend '%s': %w\", fullPath, err)\n\t}\n\tdataKey, err := dataKeyFromSecret(secret)\n\tif err != nil {\n\t\tlog.WithField(\"Path\", fullPath).Info(\"Decryption failed\")\n\t\treturn nil, fmt.Errorf(\"failed to decrypt sops data key from Vault transit backend '%s': %w\", fullPath, err)\n\t}\n\n\tlog.WithField(\"Path\", fullPath).Info(\"Decryption successful\")\n\treturn dataKey, nil\n}\n\n// NeedsRotation returns whether the data key needs to be rotated or not.\nfunc (key *MasterKey) NeedsRotation() bool {\n\t// TODO: manage rewrapping https://www.vaultproject.io/api/secret/transit/index.html#rewrap-data\n\treturn time.Since(key.CreationDate) > (vaultTTL)\n}\n\n// ToString converts the key to a string representation.","sourceCodeStart":274,"sourceCodeEnd":310,"githubUrl":"https://github.com/getsops/sops/blob/13442bb98183887d7a9ac09ec8ab0564673a59d8/hcvault/keysource.go#L274-L310","documentation":"This error wraps any failure from the Vault API when SOPS writes the encrypted data key to the transit decrypt endpoint (`<enginePath>/decrypt/<keyName>`) during MasterKey.DecryptContext. The Vault server rejected or could not perform the decryption (auth, permissions, bad ciphertext, connectivity).","triggerScenarios":"client.Logical().WriteWithContext(ctx, fullPath, decryptPayload(key.EncryptedKey)) returns an error in DecryptContext — 403 permission denied, 404 unknown key, 400 'invalid ciphertext' or empty ciphertext, or transport error.","commonSituations":"Token lacks `update` on transit/decrypt/*; the encrypted key was produced by a different transit key than the one configured in the sops file (key rotated/renamed); EncryptedKey empty or corrupted in the .sops.yaml; KeyName changed in Vault; network/TLS issues.","solutions":["Confirm the token can decrypt: `vault token lookup` and policy with `update` on `<enginePath>/decrypt/*`.","Check the .sops file's `enc` value is a valid vault ciphertext (starts with `vault:v1:`) and non-empty.","Ensure KeyName/EnginePath in the URI match the key that originally encrypted the data; if the key was renamed, update the sops config or re-encrypt.","Test manually: `vault write transit/decrypt/<keyName> ciphertext=vault:v1:...`.","Verify server reachability/TLS as with the encrypt error (vault status, curl health)."],"exampleFix":"// before: sops file encrypted with key 'sops-old' but URI says 'sops'\nhc_vault: https://vault.example.com/v1/transit/keys/sops\n// after: URI matching the key that produced the stored ciphertext\nhc_vault: https://vault.example.com/v1/transit/keys/sops-old","handlingStrategy":"try-catch","validationCode":"// Go: pre-check the stored ciphertext looks like a vault transit blob\nenc := key.EncryptedKey\nif enc == \"\" || !strings.HasPrefix(enc, \"vault:v\") {\n\treturn fmt.Errorf(\"encrypted key is not a valid vault ciphertext\")\n}","typeGuard":null,"tryCatchPattern":"dataKey, err := key.DecryptContext(ctx)\nif err != nil {\n\tvar ve *api.ResponseError\n\tif errors.As(err, &ve) && ve.StatusCode == 403 {\n\t\treturn fmt.Errorf(\"token lacks transit decrypt permission on %s: %w\", fullPath, err)\n\t}\n\treturn fmt.Errorf(\"vault decrypt failed (check key name matches encrypting key): %w\", err)\n}","preventionTips":["Never rename or delete the transit key that encrypted existing .sops files without re-encrypting them.","Ensure the decrypt policy includes `update` on `<engine>/decrypt/*`.","Validate the `enc` field in .sops.yaml starts with `vault:v1:`.","Keep tokens fresh (token renewal or short-lived CI tokens) so decryption doesn't fail mid-pipeline."],"tags":["vault","transit","decryption","authentication","ciphertext"],"backgroundTag":"vault-transit-decrypt-failed","analyzedSha":"13442bb98183887d7a9ac09ec8ab0564673a59d8","analyzedAt":"2026-09-01T03:53:00.447Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}