elsa-workflows/elsa-core · critical · InvalidOperationException

Elsa Secrets encryption key must be exactly 16, 24, or 32…

Error message

Elsa Secrets encryption key must be exactly 16, 24, or 32 bytes.

What it means

GetKey validates that SecretsOptions.EncryptionKey is exactly 16, 24, or 32 bytes (AES-128/192/256 key sizes) and throws InvalidOperationException otherwise. A key of any other length cannot be used with the AES-GCM cipher used by the protector.

Solutions

  1. Derive a properly sized key: use a KDF (e.g. Rfc2898DeriveBytes/argon2) or SHA-256 hash to get exactly 32 bytes.
  2. Ensure base64-encoded keys are decoded to bytes before assignment (Encoding/Convert.FromBase64String).
  3. Generate a fresh key of exactly 32 bytes (RandomNumberGenerator.GetBytes(32)) if no prior encrypted data exists.
  4. Caution: changing the key makes previously encrypted payloads undecryptable — re-encrypt secrets after changing keys.

Example fix

// before
options.EncryptionKey = Encoding.UTF8.GetBytes("my-secret-passphrase"); // 20 bytes -> throws
// after
using var kdf = new Rfc2898DeriveBytes("my-secret-passphrase", salt, 100_000, HashAlgorithmName.SHA256);
options.EncryptionKey = kdf.GetBytes(32); // exactly 32 bytes
Defensive patterns

Strategy: validation

Validate before calling

var key = options.EncryptionKey;
if (key is not { Length: 16 or 24 or 32 })
    throw new InvalidOperationException($"EncryptionKey must be 16/24/32 bytes; got {key?.Length ?? 0}.");

Type guard

bool IsValidKey(byte[]? key) => key is { Length: 16 or 24 or 32 };

Try / catch

try { var value = protector.Protect(plaintext); }
catch (InvalidOperationException ex) when (ex.Message.Contains("16, 24, or 32 bytes"))
{ logger.LogCritical("Secrets encryption key has invalid length: {Msg}", ex.Message); throw; }

Prevention

When it happens

Trigger: Setting SecretsOptions.EncryptionKey to a byte array whose length is not 16, 24, or 32 — commonly a raw UTF-8 password of arbitrary length, or a base64 string that was not decoded / decoded incorrectly.

Common situations: Passing a passphrase string directly instead of a properly sized key; double-encoding base64; truncating a key during copy/paste; generating a 40-byte key from a wrong hash output.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of elsa-workflows/elsa-core@fe9217bdfa (2026-09-13). Data as JSON: /api/errors/3b7e3b2820b74d9d. Report an issue: GitHub.

Appendix: source

Thrown at src/modules/Elsa.Secrets/Services/DefaultSecretValueProtector.cs:48

        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.");

        if (key.Length is not (16 or 24 or 32))
            throw new InvalidOperationException("Elsa Secrets encryption key must be exactly 16, 24, or 32 bytes.");

        return key;
    }
}

View on GitHub (pinned to fe9217bdfa)