{"record":{"id":"5a634a5d45474ac6","repo":"hashicorp/terraform","slug":"failed-to-open-state-file-at-v-v","errorCode":null,"errorMessage":"Failed to open state file at %v: %v","messagePattern":"Failed to open state file at (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/backend/remote-state/gcs/client.go","lineNumber":40,"sourceCode":"// blobs representing state.\n// Implements \"state/remote\".ClientLocker\ntype remoteClient struct {\n\tstorageClient *storage.Client\n\tbucketName    string\n\tstateFilePath string\n\tlockFilePath  string\n\tencryptionKey []byte\n\tkmsKeyName    string\n}\n\nfunc (c *remoteClient) Get() (payload *remote.Payload, diags tfdiags.Diagnostics) {\n\tctx := context.TODO()\n\tstateFileReader, err := c.stateFile().NewReader(ctx)\n\tif err != nil {\n\t\tif err == storage.ErrObjectNotExist {\n\t\t\treturn nil, diags\n\t\t} else {\n\t\t\treturn nil, diags.Append(fmt.Errorf(\"Failed to open state file at %v: %v\", c.stateFileURL(), err))\n\t\t}\n\t}\n\tdefer stateFileReader.Close()\n\n\tstateFileContents, err := ioutil.ReadAll(stateFileReader)\n\tif err != nil {\n\t\treturn nil, diags.Append(fmt.Errorf(\"Failed to read state file from %v: %v\", c.stateFileURL(), err))\n\t}\n\n\tstateFileAttrs, err := c.stateFile().Attrs(ctx)\n\tif err != nil {\n\t\treturn nil, diags.Append(fmt.Errorf(\"Failed to read state file attrs from %v: %v\", c.stateFileURL(), err))\n\t}\n\n\tresult := &remote.Payload{\n\t\tData: stateFileContents,\n\t\tMD5:  stateFileAttrs.MD5,\n\t}","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/hashicorp/terraform/blob/d32a084675427f5ac3f7d2868578ef8b2c1dc525/internal/backend/remote-state/gcs/client.go#L22-L58","documentation":"Thrown by the remote client Get when stateFile().NewReader returns an error other than storage.ErrObjectNotExist. ErrObjectNotExist is treated as 'no state yet' and is silent; any other reader-creation error (permissions, transport, transient) is wrapped here with the state file URL.","triggerScenarios":"NewReader fails with a non-NotFound error — insufficient storage.objects.get permission, network failure opening the read stream, bucket disabled, or object archived to a colder storage class requiring restoration.","commonSituations":"Service account has list but not get; transient 5xx opening the stream; the bucket was renamed; custom endpoint misroutes the read.","solutions":["Grant roles/storage.objectViewer (or objectAdmin) for the state object path.","Inspect the wrapped %v error to distinguish permission from transport failure.","Verify the bucket name and prefix are correct.","Retry transient network errors; the operation is read-only and idempotent."],"exampleFix":"// before — missing get permission\n// after\ngsutil iam ch serviceAccount:terraform@proj.iam.gserviceaccount.com:roles/storage.objectViewer gs://tf-state","handlingStrategy":"validation","validationCode":"// Pre-flight check: account can read the state object.\n// gsutil stat gs://<bucket>/<prefix>default.tfstate","typeGuard":"func isErrObjectNotExist(err error) bool { return errors.Is(err, storage.ErrObjectNotExist) }","tryCatchPattern":"// Treat NotFound as 'no state', all else as error (mirror the source).\nif errors.Is(err, storage.ErrObjectNotExist) {\n    return nil, diags // no state yet\n}\nreturn nil, diags.Append(fmt.Errorf(\"Failed to open state file at %v: %v\", url, err))","preventionTips":["Grant roles/storage.objectViewer on the bucket.","Use gsutil stat to verify access before terraform runs.","Distinguish NotFound from real errors — NotFound is benign."],"tags":["gcs","backend","storage","iam","state-read","permissions"],"backgroundTag":null,"analyzedSha":"d32a084675427f5ac3f7d2868578ef8b2c1dc525","analyzedAt":"2026-08-11T18:43:52.779Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}