{"record":{"id":"1c55dcb43a49b6f0","repo":"getsops/sops","slug":"transit-backend-is-empty","errorCode":null,"errorMessage":"transit backend is empty","messagePattern":"transit backend is empty","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"hcvault/keysource.go","lineNumber":353,"sourceCode":"\n// decryptPath returns the path for Decrypt requests.\nfunc (key *MasterKey) decryptPath() string {\n\treturn path.Join(key.EnginePath, \"decrypt\", key.KeyName)\n}\n\n// encryptPayload returns the payload for an encrypt request of the dataKey.\nfunc encryptPayload(dataKey []byte) map[string]interface{} {\n\tencoded := base64.StdEncoding.EncodeToString(dataKey)\n\treturn map[string]interface{}{\n\t\t\"plaintext\": encoded,\n\t}\n}\n\n// encryptedKeyFromSecret attempts to extract the encrypted key from the data\n// of the provided secret.\nfunc encryptedKeyFromSecret(secret *api.Secret) (string, error) {\n\tif secret == nil || secret.Data == nil {\n\t\treturn \"\", fmt.Errorf(\"transit backend is empty\")\n\t}\n\tencrypted, ok := secret.Data[\"ciphertext\"]\n\tif !ok {\n\t\treturn \"\", fmt.Errorf(\"no encrypted data\")\n\t}\n\tencryptedKey, ok := encrypted.(string)\n\tif !ok {\n\t\treturn \"\", fmt.Errorf(\"encrypted ciphertext cannot be cast to string\")\n\t}\n\treturn encryptedKey, nil\n}\n\n// decryptPayload returns the payload for a decrypt request of the\n// encryptedKey.\nfunc decryptPayload(encryptedKey string) map[string]interface{} {\n\treturn map[string]interface{}{\n\t\t\"ciphertext\": encryptedKey,\n\t}","sourceCodeStart":335,"sourceCodeEnd":371,"githubUrl":"https://github.com/getsops/sops/blob/13442bb98183887d7a9ac09ec8ab0564673a59d8/hcvault/keysource.go#L335-L371","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: engine path wrong — hits an empty/KV mount\nhc_vault: https://vault.example.com/v1/myengine/keys/sops\n// after: real transit mount\nhc_vault: https://vault.example.com/v1/transit/keys/sops","handlingStrategy":"try-catch","validationCode":"// Go: confirm a transit engine with the key exists before encrypting\nmounts, err := client.Sys().ListMounts()\nif err != nil { return err }\nm, ok := mounts[enginePath+\"/\"]\nif !ok || m.Type != \"transit\" {\n\treturn fmt.Errorf(\"engine %s is not mounted as transit\", enginePath)\n}\nif _, err := client.Logical().Read(enginePath + \"/keys/\" + keyName); err != nil {\n\treturn fmt.Errorf(\"transit key %s not found: %w\", keyName, err)\n}","typeGuard":"// Go: narrow the secret before use\nfunc secretHasData(s *api.Secret) bool {\n\treturn s != nil && s.Data != nil && len(s.Data) > 0\n}\nif !secretHasData(secret) {\n\treturn fmt.Errorf(\"vault returned an empty secret for %s\", fullPath)\n}","tryCatchPattern":"if err := key.EncryptContext(ctx, dataKey); err != nil {\n\tif strings.Contains(err.Error(), \"transit backend is empty\") {\n\t\treturn fmt.Errorf(\"vault returned an empty response; check %s is a transit mount and the server version is supported\", fullPath)\n\t}\n\treturn err\n}","preventionTips":["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."],"tags":["vault","transit","empty-response","encryption"],"backgroundTag":"vault-transit-empty-response","analyzedSha":"13442bb98183887d7a9ac09ec8ab0564673a59d8","analyzedAt":"2026-09-01T03:53:00.447Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}