hashicorp/terraform · error

Error decoding encryption key

Error message

Error decoding encryption key: %s

What it means

Thrown when the bytes read from encryption_key are not valid standard base64. The GCS backend expects a 32-byte key supplied base64-encoded (consistent with the GCS customer-supplied encryption docs), so after reading it decodes with base64.StdEncoding.

Solutions

  1. Regenerate the key as base64 of 32 random bytes: `openssl rand -base64 32`.
  2. Strip trailing whitespace/newlines from the key content before supplying it.
  3. Ensure you are using standard (not URL-safe) base64 with correct '=' padding.
  4. Confirm the decoded length is exactly 32 bytes.

Example fix

// before — raw bytes or wrong encoding
export TF_ENC_KEY=$(openssl rand 32 | base64)  # newline included
// after
export TF_ENC_KEY=$(openssl rand -base64 32 | tr -d '\n')
Defensive patterns

Strategy: validation

Validate before calling

decoded, err := base64.StdEncoding.DecodeString(strings.TrimSpace(kc))
if err != nil {
    return fmt.Errorf("encryption_key must be base64(32 bytes); regenerate with `openssl rand -base64 32`")
}
if len(decoded) != 32 {
    return fmt.Errorf("encryption_key decodes to %d bytes, expected 32", len(decoded))
}

Type guard

func isValidGCSEncryptionKey(s string) bool {
    b, err := base64.StdEncoding.DecodeString(strings.TrimSpace(s))
    return err == nil && len(b) == 32
}

Prevention

When it happens

Trigger: readPathOrContents returns content, but base64.StdEncoding.DecodeString returns an error — e.g., the key is raw bytes, hex-encoded, URL-safe base64, contains whitespace/newlines that StdEncoding rejects, or has wrong padding.

Common situations: User generated a key with `openssl rand 32` and pasted raw bytes; used `base64.URLStringEncoding`; the file has a trailing newline that breaks strict StdEncoding; key was generated by a tool emitting hex.

Related errors


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

Appendix: 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 d32a084675)