{"record":{"id":"c3e19f83ba90db82","repo":"hashicorp/terraform","slug":"error-decoding-encryption-key-s","errorCode":null,"errorMessage":"Error decoding encryption key: %s","messagePattern":"Error decoding encryption key: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/backend/remote-state/gcs/backend.go","lineNumber":281,"sourceCode":"\tkey := data.String(\"encryption_key\")\n\tif key != \"\" {\n\t\tkc, err := readPathOrContents(key)\n\t\tif err != nil {\n\t\t\treturn backendbase.ErrorAsDiagnostics(\n\t\t\t\tfmt.Errorf(\"Error loading encryption key: %s\", err),\n\t\t\t)\n\t\t}\n\n\t\t// The GCS client expects a customer supplied encryption key to be\n\t\t// passed in as a 32 byte long byte slice. The byte slice is base64\n\t\t// encoded before being passed to the API. We take a base64 encoded key\n\t\t// to remain consistent with the GCS docs.\n\t\t// https://cloud.google.com/storage/docs/encryption#customer-supplied\n\t\t// https://github.com/GoogleCloudPlatform/google-cloud-go/blob/def681/storage/storage.go#L1181\n\t\tk, err := base64.StdEncoding.DecodeString(kc)\n\t\tif err != nil {\n\t\t\treturn backendbase.ErrorAsDiagnostics(\n\t\t\t\tfmt.Errorf(\"Error decoding encryption key: %s\", err),\n\t\t\t)\n\t\t}\n\t\tb.encryptionKey = k\n\t}\n\n\t// Customer-managed encryption\n\tkmsName := data.String(\"kms_encryption_key\")\n\tif kmsName != \"\" {\n\t\tb.kmsKeyName = kmsName\n\t}\n\n\treturn nil\n}\n","sourceCodeStart":263,"sourceCodeEnd":295,"githubUrl":"https://github.com/hashicorp/terraform/blob/c9def3e214014c1188faabfc4a5bde5095139765/internal/backend/remote-state/gcs/backend.go#L263-L295","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nencryption_key = \"y0ur-keys-here-with-_urlsafe_-chars==\"  // URL-safe base64\n\n// after\n# generate a correct CSEK\nKEY=$(head -c 32 /dev/urandom | base64)\nencryption_key = \"$KEY\"   # standard base64, 44 chars ending in '='","handlingStrategy":"validation","validationCode":"// Validate CSEK shape before passing to terraform\nimport \"encoding/base64\"\nfunc validateCSEK(s string) error {\n    b, err := base64.StdEncoding.DecodeString(s)\n    if err != nil { return fmt.Errorf(\"not standard base64: %w\", err) }\n    if len(b) != 32 { return fmt.Errorf(\"decoded key is %d bytes, want 32\", len(b)) }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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."],"tags":["gcs","gcp","encryption","csek","base64","config-validation"],"analyzedSha":"c9def3e214014c1188faabfc4a5bde5095139765","analyzedAt":"2026-08-07T15:39:49.278Z","schemaVersion":2},"datasetVersion":"2026-08-07T21:17:07.882Z"}