getsops/sops · error
transit backend is empty
Error message
transit backend is empty
What it means
Returned by encryptedKeyFromSecret when the Vault transit encrypt call returns a nil secret or a secret with nil Data — i.e. the transit backend returned an empty response. It is wrapped by the EncryptContext 'failed to encrypt...' error, so developers usually see it nested under that message.
Source
Thrown at hcvault/keysource.go:353
// decryptPath returns the path for Decrypt requests.
func (key *MasterKey) decryptPath() string {
return path.Join(key.EnginePath, "decrypt", key.KeyName)
}
// encryptPayload returns the payload for an encrypt request of the dataKey.
func encryptPayload(dataKey []byte) map[string]interface{} {
encoded := base64.StdEncoding.EncodeToString(dataKey)
return map[string]interface{}{
"plaintext": encoded,
}
}
// encryptedKeyFromSecret attempts to extract the encrypted key from the data
// of the provided secret.
func encryptedKeyFromSecret(secret *api.Secret) (string, error) {
if secret == nil || secret.Data == nil {
return "", fmt.Errorf("transit backend is empty")
}
encrypted, ok := secret.Data["ciphertext"]
if !ok {
return "", fmt.Errorf("no encrypted data")
}
encryptedKey, ok := encrypted.(string)
if !ok {
return "", fmt.Errorf("encrypted ciphertext cannot be cast to string")
}
return encryptedKey, nil
}
// decryptPayload returns the payload for a decrypt request of the
// encryptedKey.
func decryptPayload(encryptedKey string) map[string]interface{} {
return map[string]interface{}{
"ciphertext": encryptedKey,
}View on GitHub (pinned to 13442bb981)
Solutions
- Verify the engine type at the path: `vault secrets list -detailed` and confirm it is `transit`.
- Test encryption manually with the Vault CLI and confirm a `ciphertext` field is returned.
- Check Vault server version and any proxy in front of it for responses with empty bodies.
- Recreate the key/mount (`vault secrets enable transit; vault write -f transit/keys/<name>`) and retry.
Example fix
// before: engine path wrong — hits an empty/KV mount hc_vault: https://vault.example.com/v1/myengine/keys/sops // after: real transit mount hc_vault: https://vault.example.com/v1/transit/keys/sops
Defensive patterns
Strategy: try-catch
Validate before calling
// Go: confirm a transit engine with the key exists before encrypting
mounts, err := client.Sys().ListMounts()
if err != nil { return err }
m, ok := mounts[enginePath+"/"]
if !ok || m.Type != "transit" {
return fmt.Errorf("engine %s is not mounted as transit", enginePath)
}
if _, err := client.Logical().Read(enginePath + "/keys/" + keyName); err != nil {
return fmt.Errorf("transit key %s not found: %w", keyName, err)
} Type guard
// Go: narrow the secret before use
func secretHasData(s *api.Secret) bool {
return s != nil && s.Data != nil && len(s.Data) > 0
}
if !secretHasData(secret) {
return fmt.Errorf("vault returned an empty secret for %s", fullPath)
} Try / catch
if err := key.EncryptContext(ctx, dataKey); err != nil {
if strings.Contains(err.Error(), "transit backend is empty") {
return fmt.Errorf("vault returned an empty response; check %s is a transit mount and the server version is supported", fullPath)
}
return err
} Prevention
- Point sops URIs only at transit engines (`vault secrets enable transit`).
- Create the key up front: `vault write -f transit/keys/<name>`.
- Smoke-test the encrypt endpoint via CLI before relying on it in automation.
- Keep Vault server reasonably current; very old versions/proxies may return empty bodies on transit writes.
When it happens
Trigger: EncryptContext calls encryptedKeyFromSecret(secret) after a successful write, but secret == nil or secret.Data == nil, producing 'transit backend is empty'. Callers: EncryptContext, TestMasterKey_Decrypt, and an anonymous test function.
Common situations: The configured path is not a transit mount (writes succeed silently elsewhere); an intermediary (proxy, older Vault version, bug) returns a 200 with an empty body; misconfigured namespace causing an empty response.
Related errors
- failed to encrypt sops data key to Vault transit backend '%s
- encryption response missing ciphertext
- failed to decrypt sops data key from Vault transit backend '
- 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/1c55dcb43a49b6f0.
Report an issue: GitHub.