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
- Verify the path exists and is readable by the terraform process: 'ls -l <path>' and 'test -r <path>'.
- If the value is the key content itself (base64 string), confirm it doesn't contain '/' prefixes that make readPathOrContents treat it as a path.
- 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.
- 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
- Mount the secret at the configured path in every environment that runs terraform.
- Use the GOOGLE_ENCRYPTION_KEY env var to avoid path coupling in CI.
- Add a 'test -r <path>' step before 'terraform init' in pipelines.
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
- Error decoding 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/aed02b995e739bf2.
Report an issue: GitHub.