elsa-workflows/elsa-core · error · InvalidOperationException
The protected secret payload is not supported.
Error message
The protected secret payload is not supported.
What it means
DefaultSecretValueProtector.Unprotect parses protected values of the form 'v1.<nonce>.<tag>.<ciphertext>' (4 dot-separated base64 parts). Values that do not match this exact versioned envelope are rejected with InvalidOperationException. Typically the value was not produced by this protector (plaintext, or encrypted by a different tool/format).
Solutions
- Encrypt the plaintext value with the protector (Protect) before storing it.
- Confirm the stored value came from the same protector version ('v1') and re-encrypt with the current version if not.
- Re-enter the protected value without corruption (check for trimmed/stripped characters).
- If migrating formats, write a migration that decrypts with the old scheme and re-protects with v1.
Example fix
// before
await secretManager.CreateSecretAsync(new CreateSecretRequest { Name = "ApiKey", PlainTextValue = "sk-live-abc123" }); // plaintext into encrypted path
// after
var protectedValue = protector.Protect("sk-live-abc123");
await secretManager.CreateSecretAsync(new CreateSecretRequest { Name = "ApiKey", ProtectedValue = protectedValue }); Defensive patterns
Strategy: type-guard
Validate before calling
static bool IsProtectedFormat(string value)
{
var parts = value.Split('.');
return parts.Length == 4 && parts[0] == "v1" &&
parts.Skip(1).All(p => Convert.TryFromBase64String(p, new byte[p.Length * 3 / 4 + 3], out _));
} Type guard
bool LooksProtected(string? value) =>
!string.IsNullOrWhiteSpace(value) && value.Split('.').Length == 4 && value.StartsWith("v1.", StringComparison.Ordinal); Try / catch
try { var plain = protector.Unprotect(stored); }
catch (InvalidOperationException ex) when (ex.Message.Contains("not supported"))
{ logger.LogError("Value for secret is not in v1 protected format; re-encrypt it"); throw; } Prevention
- Always run plaintext through Protect before storing in encrypted fields
- Version-tag future format changes and handle them explicitly
- Validate pasted values match the v1 envelope
- Re-protect values when migrating between encryption schemes
When it happens
Trigger: Unprotect (or decrypting resolve paths) receiving a string that is not 4 dot-separated parts or whose prefix is not 'v1' — e.g. a plaintext secret pasted into an encrypted field, or a payload from another/older encryption scheme.
Common situations: Storing raw plaintext where the store expects protector output; encryption format version bumped; values encrypted by a previous implementation or external tool; copy/paste corruption dropping characters.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- A value is required for encrypted secrets.
- Elsa Secrets encryption key is not configured. Configure…
- Elsa Secrets encryption key must be exactly 16, 24, or 32…
- A configuration key is required.
- A managed secret writer returned the live secret reference…
AI-assisted analysis of elsa-workflows/elsa-core@fe9217bdfa (2026-09-13).
Data as JSON: /api/errors/875b48c6785d1f60.
Report an issue: GitHub.
Appendix: source
Thrown at src/modules/Elsa.Secrets/Services/DefaultSecretValueProtector.cs:28
public string Protect(string value)
{
var nonce = RandomNumberGenerator.GetBytes(NonceSize);
var plaintext = System.Text.Encoding.UTF8.GetBytes(value);
var ciphertext = new byte[plaintext.Length];
var tag = new byte[TagSize];
using var aes = new AesGcm(GetKey(), TagSize);
aes.Encrypt(nonce, plaintext, ciphertext, tag);
return string.Join(".", "v1", Convert.ToBase64String(nonce), Convert.ToBase64String(tag), Convert.ToBase64String(ciphertext));
}
public string Unprotect(string protectedValue)
{
var parts = protectedValue.Split('.');
if (parts.Length != 4 || parts[0] != "v1")
throw new InvalidOperationException("The protected secret payload is not supported.");
var nonce = Convert.FromBase64String(parts[1]);
var tag = Convert.FromBase64String(parts[2]);
var ciphertext = Convert.FromBase64String(parts[3]);
var plaintext = new byte[ciphertext.Length];
using var aes = new AesGcm(GetKey(), TagSize);
aes.Decrypt(nonce, ciphertext, tag, plaintext);
return System.Text.Encoding.UTF8.GetString(plaintext);
}
private byte[] GetKey()
{
var key = options.Value.EncryptionKey;
if (key == null || key.Length == 0)
throw new InvalidOperationException("Elsa Secrets encryption key is not configured. Configure SecretsOptions.EncryptionKey before using the encrypted secrets store.");
View on GitHub (pinned to fe9217bdfa)