getsops/sops · error
decrypted plaintext data cannot be cast to string
Error message
decrypted plaintext data cannot be cast to string
What it means
This error is returned by dataKeyFromSecret when secret.Data["plaintext"] exists but is not a Go string. Vault's transit decrypt returns plaintext as a base64 string; any other JSON type breaks the type assertion, so the helper fails fast instead of guessing.
Source
Thrown at hcvault/keysource.go:386
func decryptPayload(encryptedKey string) map[string]interface{} {
return map[string]interface{}{
"ciphertext": encryptedKey,
}
}
// dataKeyFromSecret attempts to extract the data key from the data of the
// provided secret.
func dataKeyFromSecret(secret *api.Secret) ([]byte, error) {
if secret == nil || secret.Data == nil {
return nil, fmt.Errorf("transit backend is empty")
}
decrypted, ok := secret.Data["plaintext"]
if !ok {
return nil, fmt.Errorf("no decrypted data")
}
plaintext, ok := decrypted.(string)
if !ok {
return nil, fmt.Errorf("decrypted plaintext data cannot be cast to string")
}
dataKey, err := base64.StdEncoding.DecodeString(plaintext)
if err != nil {
return nil, fmt.Errorf("cannot decode base64 plaintext into data key bytes")
}
return dataKey, nil
}
// vaultClient returns a new Vault client, configured with the given address
// and token.
func vaultClient(address, token string, hc *http.Client) (*api.Client, error) {
cfg := api.DefaultConfig()
cfg.Address = address
allowlist, err := getAllowlist()
if err != nil {
return nil, err
}View on GitHub (pinned to 13442bb981)
Solutions
- Inspect the raw decrypt response (`vault write -format=json transit/decrypt/<key> ciphertext=...`) and confirm data.plaintext is a base64 string.
- Fix any mock/stub to return {"plaintext":"<base64>"} with a string type.
- Upgrade or align the Vault-compatible server so its transit decrypt response matches the standard schema.
- Remove proxies/plugins that transform the JSON response between Vault and the client.
Example fix
// before: malformed mock response
{"data":{"plaintext":12345}}
// after: transit-compatible response
{"data":{"plaintext":"c3VwZXJzZWNyZXQ="}} Defensive patterns
Strategy: type-guard
Validate before calling
raw, ok := secret.Data["plaintext"]
plaintext, isStr := raw.(string)
if !ok || !isStr {
return fmt.Errorf("unexpected plaintext type %T; transit response schema mismatch", raw)
}
if _, err := base64.StdEncoding.DecodeString(plaintext); err != nil {
return fmt.Errorf("plaintext is not valid base64")
} Type guard
func asPlaintextString(secret *api.Secret) (string, bool) {
if secret == nil || secret.Data == nil { return "", false }
if v, ok := secret.Data["plaintext"]; ok {
if s, isStr := v.(string); isStr { return s, true }
}
return "", false
} Try / catch
dataKey, err := dataKeyFromSecret(secret)
if err != nil {
if strings.Contains(err.Error(), "cannot be cast to string") {
return fmt.Errorf("vault transit decrypt response schema mismatch (plaintext not a string): %w", err)
}
return err
} Prevention
- Keep mocks aligned with the real transit decrypt JSON schema
- Test against real Vault (dev mode) in CI rather than only stubs
- Log %T of the offending field when schema drift is suspected
- Pin versions of Vault-compatible servers used in the pipeline
When it happens
Trigger: DecryptContext (or TestMasterKey_Encrypt) receives a secret whose Data["plaintext"] is a non-string (number, bool, object) — typically from a mocked Vault response, a divergent Vault-compatible server, or middleware altering JSON types.
Common situations: Unit-test stubs returning plaintext as raw bytes/number instead of a base64 string; OpenBao or other Vault forks with changed response encoding; ingress proxies or custom plugins reshaping the decrypt response.
Related errors
- encrypted ciphertext cannot be cast to string
- no encrypted data
- no decrypted data
- failed to encrypt sops data key to Vault transit backend '%s
- failed to decrypt sops data key from Vault transit backend '
AI-assisted analysis of getsops/sops@13442bb981 (2026-09-01).
Data as JSON: /api/errors/ca101ff0299ca94c.
Report an issue: GitHub.