hashicorp/terraform · error

error downloading state

Error message

error downloading state: %v

What it means

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.

Solutions

  1. Retry the terraform command — presigned URL expiry and transient storage errors often resolve on retry
  2. Verify network egress allows the object storage domain (check the DownloadURL host, not just the TFE API host)
  3. On self-hosted TFE, confirm the object storage backend is healthy and the TFE instance can reach it
  4. Check the TFE workspace state version list in the UI to confirm the latest state version is downloadable
Defensive patterns

Strategy: retry

Validate before calling

// Before RefreshState, verify object storage reachability if self-hosted:
if isSelfHostedTFE {
    // check the configured storage endpoint is reachable
    if err := checkStorageConnectivity(tfEndpoint); err != nil {
        return fmt.Errorf("object storage unreachable, state download will fail: %w", err)
    }
}

Try / catch

// Download failures from presigned URLs are often transient — retry:
for attempt := 0; attempt < 3; attempt++ {
    err := stateMgr.RefreshState()
    if err == nil || !strings.Contains(err.Error(), "error downloading state") {
        return err
    }
    log.Printf("state download attempt %d failed, retrying", attempt+1)
    time.Sleep(time.Duration(attempt+1) * 2 * time.Second)
}
return fmt.Errorf("state download failed after retries")

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11). Data as JSON: /api/errors/2e83cebad7c04037. Report an issue: GitHub.

Appendix: source

Thrown at internal/cloud/state.go:422

func (s *State) getStatePayload() (*remote.Payload, error) {
	ctx := context.Background()

	// Check the x-terraform-snapshot-interval header to see if it has a non-empty
	// value which would indicate snapshots are enabled
	ctx = tfe.ContextWithResponseHeaderHook(ctx, s.readSnapshotIntervalHeader)

	sv, err := s.tfeClient.StateVersions.ReadCurrent(ctx, s.workspace.ID)
	if err != nil {
		if err == tfe.ErrResourceNotFound {
			// If no state exists, then return nil.
			return nil, nil
		}
		return nil, fmt.Errorf("error retrieving state: %v", err)
	}

	state, err := s.tfeClient.StateVersions.Download(ctx, sv.DownloadURL)
	if err != nil {
		return nil, fmt.Errorf("error downloading state: %v", err)
	}

	// If the state is empty, then return nil.
	if len(state) == 0 {
		return nil, nil
	}

	// Get the MD5 checksum of the state.
	sum := md5.Sum(state)

	return &remote.Payload{
		Data: state,
		MD5:  sum[:],
	}, nil
}

type errorUnlockFailed struct {
	innerError error

View on GitHub (pinned to d32a084675)