{"record":{"id":"2e83cebad7c04037","repo":"hashicorp/terraform","slug":"error-downloading-state-v-2e83ce","errorCode":null,"errorMessage":"error downloading state: %v","messagePattern":"error downloading state: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/cloud/state.go","lineNumber":422,"sourceCode":"func (s *State) getStatePayload() (*remote.Payload, error) {\n\tctx := context.Background()\n\n\t// Check the x-terraform-snapshot-interval header to see if it has a non-empty\n\t// value which would indicate snapshots are enabled\n\tctx = tfe.ContextWithResponseHeaderHook(ctx, s.readSnapshotIntervalHeader)\n\n\tsv, err := s.tfeClient.StateVersions.ReadCurrent(ctx, s.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, fmt.Errorf(\"error retrieving state: %v\", err)\n\t}\n\n\tstate, err := s.tfeClient.StateVersions.Download(ctx, sv.DownloadURL)\n\tif err != nil {\n\t\treturn nil, 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\ntype errorUnlockFailed struct {\n\tinnerError error","sourceCodeStart":404,"sourceCodeEnd":440,"githubUrl":"https://github.com/hashicorp/terraform/blob/d32a084675427f5ac3f7d2868578ef8b2c1dc525/internal/cloud/state.go#L404-L440","documentation":"Thrown in getStatePayload after StateVersions.ReadCurrent succeeds but StateVersions.Download fails to fetch the actual state bytes from the DownloadURL. The download uses a separate (often presigned, S3-style) URL distinct from the TFE API endpoint, so it can fail even when the API is healthy. The %v embeds the raw download error.","triggerScenarios":"The presigned download URL expired before the HTTP GET was issued; the object storage backend (S3, Azure blob, GCS) is unavailable; network firewall blocks the object storage domain while allowing the TFE API domain; CORS or TLS issues with the storage endpoint; the state artifact was deleted between ReadCurrent and Download.","commonSituations":"Self-hosted TFE with misconfigured or temporarily-down object storage; cloud egress firewall rules that allow app.terraform.io but block the underlying S3/Azure bucket domain; slow network where the presigned URL times out before the download starts; TFE backup/restore in progress affecting storage.","solutions":["Retry the terraform command — presigned URL expiry and transient storage errors often resolve on retry","Verify network egress allows the object storage domain (check the DownloadURL host, not just the TFE API host)","On self-hosted TFE, confirm the object storage backend is healthy and the TFE instance can reach it","Check the TFE workspace state version list in the UI to confirm the latest state version is downloadable"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Before RefreshState, verify object storage reachability if self-hosted:\nif isSelfHostedTFE {\n    // check the configured storage endpoint is reachable\n    if err := checkStorageConnectivity(tfEndpoint); err != nil {\n        return fmt.Errorf(\"object storage unreachable, state download will fail: %w\", err)\n    }\n}","typeGuard":null,"tryCatchPattern":"// Download failures from presigned URLs are often transient — retry:\nfor attempt := 0; attempt < 3; attempt++ {\n    err := stateMgr.RefreshState()\n    if err == nil || !strings.Contains(err.Error(), \"error downloading state\") {\n        return err\n    }\n    log.Printf(\"state download attempt %d failed, retrying\", attempt+1)\n    time.Sleep(time.Duration(attempt+1) * 2 * time.Second)\n}\nreturn fmt.Errorf(\"state download failed after retries\")","preventionTips":["Ensure CI/network egress allows the object storage domain, not just the TFE API domain","For self-hosted TFE, monitor object storage health as part of platform readiness checks","Retry RefreshState once or twice before failing a pipeline, as presigned URL expiry is transient"],"tags":["network","state-refresh","tfe","download","object-storage","terraform"],"backgroundTag":null,"analyzedSha":"d32a084675427f5ac3f7d2868578ef8b2c1dc525","analyzedAt":"2026-08-11T18:43:52.779Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}