hashicorp/terraform · error

Error loading encryption key: %s

Error message

Error loading encryption key: %s

What it means

The GCS backend allows customer-supplied encryption via 'encryption_key'. The value is passed through readPathOrContents, which treats it as a file path first and falls back to treating it as the literal content. If neither resolves (file does not exist / unreadable), this error is returned with the OS error in %s. It fires before any base64 decoding is attempted.

Source

Thrown at internal/backend/remote-state/gcs/backend.go:268

		endpoint := option.WithEndpoint(storageEndpoint)
		opts = append(opts, endpoint)
	}
	client, err := storage.NewClient(ctx, opts...)
	if err != nil {
		return backendbase.ErrorAsDiagnostics(
			fmt.Errorf("storage.NewClient() failed: %v", err),
		)
	}

	b.storageClient = client

	// Customer-supplied encryption
	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
	}

View on GitHub (pinned to c9def3e214)

Solutions

  1. Verify the path exists and is readable by the terraform process: 'ls -l <path>' and 'test -r <path>'.
  2. If the value is the key content itself (base64 string), confirm it doesn't contain '/' prefixes that make readPathOrContents treat it as a path.
  3. Mount the secret at the configured path in CI (Vault/secret manager sidecar) or switch to passing the value via the GOOGLE_ENCRYPTION_KEY env var.
  4. If you migrated to KMS, remove encryption_key and use kms_encryption_key instead.

Example fix

// before
encryption_key = "/run/secrets/gcs-csek"   # not mounted in CI

// after
encryption_key = file("${path.module}/keys/gcs-csek.b64")
# or via env
export GOOGLE_ENCRYPTION_KEY=$(cat keys/gcs-csek.b64)
Defensive patterns

Strategy: validation

Validate before calling

// Verify the CSEK file is readable before invoking terraform
path := "/run/secrets/gcs-csek"
if _, err := os.ReadFile(path); err != nil {
    log.Fatalf("encryption_key path unreadable: %v", err)
}

Prevention

When it happens

Trigger: encryption_key set to a path like '/run/secrets/gcs-key' that doesn't exist on the runner, or set via GOOGLE_ENCRYPTION_KEY to a path the process can't read, during 'terraform init' in Configure().

Common situations: Secret mounted to a different path in CI vs local; typo in the path; permission bits on the key file; encryption_key value intended as inline content but accidentally looks like a path.

Related errors


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