hashicorp/terraform · error
Error decoding encryption key: %s
Error message
Error decoding encryption key: %s
What it means
After the encryption_key content is loaded, the GCS backend expects a standard base64-encoded 32-byte key and calls base64.StdEncoding.DecodeString on it. If decoding fails (illegal characters, wrong length, URL-safe base64 used instead of standard), this error wraps the base64.CorruptInputError. The decoded bytes must be exactly 32 bytes for GCS CSEK.
Source
Thrown at internal/backend/remote-state/gcs/backend.go:281
key := data.String("encryption_key")
if key != "" {
kc, err := readPathOrContents(key)
if err != nil {
return backendbase.ErrorAsDiagnostics(
fmt.Errorf("Error loading encryption key: %s", err),
)
}
// The GCS client expects a customer supplied encryption key to be
// passed in as a 32 byte long byte slice. The byte slice is base64
// encoded before being passed to the API. We take a base64 encoded key
// to remain consistent with the GCS docs.
// https://cloud.google.com/storage/docs/encryption#customer-supplied
// https://github.com/GoogleCloudPlatform/google-cloud-go/blob/def681/storage/storage.go#L1181
k, err := base64.StdEncoding.DecodeString(kc)
if err != nil {
return backendbase.ErrorAsDiagnostics(
fmt.Errorf("Error decoding encryption key: %s", err),
)
}
b.encryptionKey = k
}
// Customer-managed encryption
kmsName := data.String("kms_encryption_key")
if kmsName != "" {
b.kmsKeyName = kmsName
}
return nil
}
View on GitHub (pinned to c9def3e214)
Solutions
- Regenerate the key as 32 random bytes and standard-base64-encode it: 'head -c 32 /dev/urandom | base64'.
- Confirm the value has no newlines/spaces and uses '+' and '/' (not '-' and '_').
- If you only have a URL-safe key, convert it: tr '_-' '/+' before passing to the backend.
- Verify the decoded length is exactly 32: 'echo -n "$KEY" | base64 -d | wc -c' should print 32.
Example fix
// before encryption_key = "y0ur-keys-here-with-_urlsafe_-chars==" // URL-safe base64 // after # generate a correct CSEK KEY=$(head -c 32 /dev/urandom | base64) encryption_key = "$KEY" # standard base64, 44 chars ending in '='
Defensive patterns
Strategy: validation
Validate before calling
// Validate CSEK shape before passing to terraform
import "encoding/base64"
func validateCSEK(s string) error {
b, err := base64.StdEncoding.DecodeString(s)
if err != nil { return fmt.Errorf("not standard base64: %w", err) }
if len(b) != 32 { return fmt.Errorf("decoded key is %d bytes, want 32", len(b)) }
return nil
} Prevention
- Always generate CSEK as 'head -c 32 /dev/urandom | base64'.
- Never URL-safe-encode the key.
- Add a CI step that validates key length == 32 bytes after decode.
When it happens
Trigger: encryption_key content is not valid standard base64 (e.g. contains '-' or '_' from base64.URL encoding, or is raw bytes / a hex string, or truncated). Triggered during 'terraform init' after the key loads successfully.
Common situations: Key generated with 'base64 -w0' on a 32-byte random value but copied with URL-safe alphabet; someone pasted the raw key; key was re-encoded as base64 twice; key length mismatch.
Related errors
- Error loading encryption key: %s
- Failed to open state file at %v: %v
- can't set both encryption_key and kms_encryption_key
- impersonate_service_account_delegates elements must not be n
- cowardly refusing to delete the %q state
AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07).
Data as JSON: /api/errors/c3e19f83ba90db82.
Report an issue: GitHub.