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

  1. Regenerate the key as 32 random bytes and standard-base64-encode it: 'head -c 32 /dev/urandom | base64'.
  2. Confirm the value has no newlines/spaces and uses '+' and '/' (not '-' and '_').
  3. If you only have a URL-safe key, convert it: tr '_-' '/+' before passing to the backend.
  4. 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

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


AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07). Data as JSON: /api/errors/c3e19f83ba90db82. Report an issue: GitHub.