{"record":{"id":"e5ea6b06301fea2b","repo":"hashicorp/terraform","slug":"error-downloading-state-v","errorCode":null,"errorMessage":"Error downloading state: %v","messagePattern":"Error downloading state: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/backend/remote/backend_state.go","lineNumber":67,"sourceCode":"var _ Fatal = errorUnlockFailed{}\n\n// Get the remote state.\nfunc (r *remoteClient) Get() (*remote.Payload, tfdiags.Diagnostics) {\n\tvar diags tfdiags.Diagnostics\n\tctx := context.Background()\n\n\tsv, err := r.client.StateVersions.ReadCurrent(ctx, r.workspace.ID)\n\tif err != nil {\n\t\tif err == tfe.ErrResourceNotFound {\n\t\t\t// If no state exists, then return nil.\n\t\t\treturn nil, nil\n\t\t}\n\t\treturn nil, diags.Append(fmt.Errorf(\"Error retrieving state: %v\", err))\n\t}\n\n\tstate, err := r.client.StateVersions.Download(ctx, sv.DownloadURL)\n\tif err != nil {\n\t\treturn nil, diags.Append(fmt.Errorf(\"Error downloading state: %v\", err))\n\t}\n\n\t// If the state is empty, then return nil.\n\tif len(state) == 0 {\n\t\treturn nil, nil\n\t}\n\n\t// Get the MD5 checksum of the state.\n\tsum := md5.Sum(state)\n\n\treturn &remote.Payload{\n\t\tData: state,\n\t\tMD5:  sum[:],\n\t}, nil\n}\n\nfunc (r *remoteClient) uploadStateFallback(ctx context.Context, stateFile *statefile.File, state []byte, jsonStateOutputs []byte) error {\n\toptions := tfe.StateVersionCreateOptions{","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/hashicorp/terraform/blob/c9def3e214014c1188faabfc4a5bde5095139765/internal/backend/remote/backend_state.go#L49-L85","documentation":"Emitted by remoteClient.Get (backend_state.go:65-68) after ReadCurrent succeeds but StateVersions.Download fails. The current state version metadata includes a DownloadURL; this code fetches the raw state bytes from that (often pre-signed, time-limited) URL. Failure means the metadata was readable but the actual state blob could not be retrieved.","triggerScenarios":"The pre-signed DownloadURL has expired before the request was issued; the object storage backend (S3 etc.) is unavailable or throttling; a network/proxy blocks the storage host distinct from the API host; the URL was revoked because a newer state version superseded this one mid-operation.","commonSituations":"Long pause between ReadCurrent and Download (e.g. slow CI runner) so the signed URL expires; egress-restricted network that allows app.terraform.io but blocks the object-storage domain; transient S3 5xx; large state file hitting a proxy body-size limit.","solutions":["Retry the command immediately — a fresh ReadCurrent yields a fresh signed DownloadURL.","Allowlist the object-storage egress domain (e.g. *.amazonaws.com) in firewall/proxy alongside the TFC API host.","Reduce state size / split workspaces if downloads repeatedly hit proxy body-size or timeout limits.","Check the TFC status page for object-storage incidents."],"exampleFix":"// before: pre-signed URL expired in a slow CI step\n$ terraform plan\nError: Error downloading state: 403 Forbidden\n\n// after: retry issues a fresh signed URL\n$ terraform plan   # succeeds on retry","handlingStrategy":"retry","validationCode":"// Confirm the workspace's current state version has a usable download URL preflight.\nsv, err := r.client.StateVersions.ReadCurrent(ctx, r.workspace.ID)\nif err != nil { return err }\nif sv.DownloadURL == \"\" { return errors.New(\"no download URL available; retry ReadCurrent\") }","typeGuard":null,"tryCatchPattern":"// Re-fetch the (freshly signed) state version then retry the download once.\nstate, err := r.client.StateVersions.Download(ctx, sv.DownloadURL)\nif err != nil {\n    sv, rerr := r.client.StateVersions.ReadCurrent(ctx, r.workspace.ID)\n    if rerr == nil {\n        state, err = r.client.StateVersions.Download(ctx, sv.DownloadURL)\n    }\n}\nif err != nil { return nil, diags.Append(fmt.Errorf(\"Error downloading state: %v\", err)) }","preventionTips":["Minimize the gap between ReadCurrent and Download in automation to avoid signed-URL expiry.","Allowlist the object-storage domain (e.g. *.amazonaws.com) alongside the TFC API host.","Retry on transient download failures before surfacing the error.","Keep state small (split workspaces) to avoid proxy body-size/timeout limits."],"tags":["state","remote-backend","download","network","object-storage","terraform-cloud"],"analyzedSha":"c9def3e214014c1188faabfc4a5bde5095139765","analyzedAt":"2026-08-07T15:39:49.278Z","schemaVersion":2},"datasetVersion":"2026-08-07T21:17:07.882Z"}