getsops/sops · error
encrypted ciphertext cannot be cast to string
Error message
encrypted ciphertext cannot be cast to string
What it means
This error is returned by encryptedKeyFromSecret when secret.Data["ciphertext"] exists but is not a Go string. Vault normally returns ciphertext as a JSON string; a non-string value means the response shape deviates from the transit API contract, so the helper refuses to unsafe-cast it.
Source
Thrown at hcvault/keysource.go:361
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,
}
}
// 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")
}View on GitHub (pinned to 13442bb981)
Solutions
- Inspect the raw Vault response (vault write -format=json transit/encrypt/<key> ...) and confirm data.ciphertext is a quoted string.
- Remove or fix any mock/stub returning ciphertext as a non-string; update it to return {"ciphertext":"vault:v1:..."}.
- If using a Vault-compatible server, upgrade to a version that matches the transit API response schema.
- Rule out response-rewriting proxies/ingress that change JSON types between Vault and the client.
Example fix
// before: mock returns wrong type
{"data":{"ciphertext":12345}}
// after: transit-compatible response
{"data":{"ciphertext":"vault:v1:8SDd3WHDO..."}} Defensive patterns
Strategy: type-guard
Validate before calling
// Before trusting the field, narrow its type
raw, ok := secret.Data["ciphertext"]
ciphertext, isStr := raw.(string)
if !ok || !isStr {
return fmt.Errorf("unexpected ciphertext type %T; transit response schema mismatch", raw)
} Type guard
func asCiphertextString(secret *api.Secret) (string, bool) {
if secret == nil || secret.Data == nil { return "", false }
if v, ok := secret.Data["ciphertext"]; ok {
if s, isStr := v.(string); isStr { return s, true }
}
return "", false
} Try / catch
key, err := encryptedKeyFromSecret(secret)
if err != nil {
if strings.Contains(err.Error(), "cannot be cast to string") {
// log raw response type and fail with a clear schema-mismatch message
return fmt.Errorf("vault transit response schema mismatch (ciphertext not a string): %w", err)
}
return err
} Prevention
- Use the official hashicorp/vault api client instead of hand-rolled HTTP mocks
- Keep test stubs' JSON schemas identical to real transit responses
- Pin Vault-compatible server versions known to match the transit API
- Log %T of unexpected fields to catch schema drift early
When it happens
Trigger: EncryptContext (or TestMasterKey_Decrypt) receives an api.Secret whose Data["ciphertext"] holds a non-string type — e.g. a map or bool — because a proxy/mock returned malformed JSON, or a custom Vault-like service returned a differently typed field.
Common situations: Running against Vault dev-mode mocks or stubs in tests with wrong field types; third-partyVault-compatible servers (e.g. OpenBao forks) with divergent response encoding; HTTP middlewares mangling JSON types.
Related errors
- decrypted plaintext data 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/3299f0459ef8e840.
Report an issue: GitHub.