getsops/sops · error
failed to decrypt sops data key from Vault transit backend '
Error message
failed to decrypt sops data key from Vault transit backend '%s': %w
What it means
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).
Source
Thrown at hcvault/keysource.go:292
// Consider using DecryptContext instead.
func (key *MasterKey) Decrypt() ([]byte, error) {
return key.DecryptContext(context.Background())
}
// DecryptContext decrypts the EncryptedKey field with Vault Transit and returns the result.
func (key *MasterKey) DecryptContext(ctx context.Context) ([]byte, error) {
fullPath := key.decryptPath()
client, err := vaultClient(key.VaultAddress, key.token, key.httpClient)
if err != nil {
log.WithField("Path", fullPath).Info("Decryption failed")
return nil, err
}
secret, err := client.Logical().WriteWithContext(ctx, fullPath, decryptPayload(key.EncryptedKey))
if err != nil {
log.WithField("Path", fullPath).Info("Decryption failed")
return nil, fmt.Errorf("failed to decrypt sops data key from Vault transit backend '%s': %w", fullPath, err)
}
dataKey, err := dataKeyFromSecret(secret)
if err != nil {
log.WithField("Path", fullPath).Info("Decryption failed")
return nil, fmt.Errorf("failed to decrypt sops data key from Vault transit backend '%s': %w", fullPath, err)
}
log.WithField("Path", fullPath).Info("Decryption successful")
return dataKey, nil
}
// NeedsRotation returns whether the data key needs to be rotated or not.
func (key *MasterKey) NeedsRotation() bool {
// TODO: manage rewrapping https://www.vaultproject.io/api/secret/transit/index.html#rewrap-data
return time.Since(key.CreationDate) > (vaultTTL)
}
// ToString converts the key to a string representation.View on GitHub (pinned to 13442bb981)
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).
Example fix
// before: sops file encrypted with key 'sops-old' but URI says 'sops' hc_vault: https://vault.example.com/v1/transit/keys/sops // after: URI matching the key that produced the stored ciphertext hc_vault: https://vault.example.com/v1/transit/keys/sops-old
Defensive patterns
Strategy: try-catch
Validate before calling
// Go: pre-check the stored ciphertext looks like a vault transit blob
enc := key.EncryptedKey
if enc == "" || !strings.HasPrefix(enc, "vault:v") {
return fmt.Errorf("encrypted key is not a valid vault ciphertext")
} Try / catch
dataKey, err := key.DecryptContext(ctx)
if err != nil {
var ve *api.ResponseError
if errors.As(err, &ve) && ve.StatusCode == 403 {
return fmt.Errorf("token lacks transit decrypt permission on %s: %w", fullPath, err)
}
return fmt.Errorf("vault decrypt failed (check key name matches encrypting key): %w", err)
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- failed to encrypt sops data key to Vault transit backend '%s
- failed to get Azure token credential to decrypt: %w
- transit backend is empty
- no encrypted data
- encrypted ciphertext cannot be cast to string
AI-assisted analysis of getsops/sops@13442bb981 (2026-09-01).
Data as JSON: /api/errors/62ca0f75937812a2.
Report an issue: GitHub.