Error: Invalid expression - A single static variable reference is required
Fixes OpenTofu's 'Error: Invalid expression - A single static variable reference is required' in encryption blocks. Use when an encryption key_provider passphrase uses anything but a bare variable reference. Not for wrong passphrases or missing keys.
TL;DR: Inside encryption {} key providers, the passphrase must be a BARE variable reference (var.state_passphrase), not an expression, function call, or conditional. Anything fancier fails with Invalid expression. Keep the secret out of shell history by exporting it as an env var the variable reads.
Error: Invalid expression
A single static variable reference is requiredSteps
- Find the offending argument in the
encryption {}block (usuallykey_provider "pbkdf2"passphrase).
Expected: something like passphrase = var.prefix + "-suffix" or passphrase = coalesce(...).
- Replace it with a single static variable reference:
encryption {
key_provider "pbkdf2" "passphrase" {
passphrase = var.state_passphrase
}
...
} Expected: the argument is exactly var.[name].
- Supply the value out of band:
export TF_VAR_state_passphrase='[your passphrase]'(or a.tfvarsfile that is gitignored).
Expected: no secret in the config or shell history.
- Re-run.
Expected: the Invalid expression error is gone.
When this applies
Error: Invalid expression/A single static variable reference is requiredpointing at anencryption {}block.- The passphrase argument contains concatenation, conditionals, or functions.
When it doesn't apply
Missing required argumenton the key_provider: the argument is absent entirely, different fix.- Wrong passphrase at runtime: that's a decryption failure, not an expression error.
Tool versions
OpenTofu 1.7+ (native state encryption).
Why it happens
The encryption configuration is evaluated before variables are fully resolved, in a restricted context where only static references are allowed. Expressions would need the full evaluation machinery that isn't available that early, so tofu rejects them outright instead of half-evaluating.
Edge cases
- PBKDF2 passphrases must be at least 16 characters; a shorter one fails at the key provider with a different error. Generate a long one.
enforced = truerefuses to write unencrypted state; enable it only once every collaborator and CI job has the passphrase, or you'll lock the team out.- Anything reading state WITHOUT the encryption config (CI linters,
tofu init -backend=falsegates, jq one-liners) sees an opaque envelope, not an error naming encryption; teach the team that envelope means "missing encryption config".