hashicorp/terraform · error

error downloading state: %v

Error message

error downloading state: %v

What it means

After reading current-state-version metadata, Terraform downloads the actual state bytes from sv.DownloadURL via StateVersions.Download. This wraps any failure of that download: the (often expiring) download URL may be unreachable, expired, or the object-storage backend unavailable.

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 c9def3e214)

Solutions

  1. Ensure network egress permits BOTH the HCP/TFE API host and the state storage host.
  2. Retry immediately; a fresh download URL is issued each time.
  3. Reduce state size (split workspaces) if downloads repeatedly time out.
  4. Check proxy/TLS-interception settings that may break the download.

Example fix

# before: egress firewall allows api host but blocks state storage host -> download fails
# after: allow egress to the state storage hostname (e.g. S3 backend domain), then refresh
terraform refresh
Defensive patterns

Strategy: retry

Try / catch

if err := state.RefreshState(); err != nil {
    if isTransientHTTP(err) || isDownloadError(err) {
        // bounded retry; a fresh DownloadURL is issued each ReadCurrent
    }
}

Prevention

When it happens

Trigger: getStatePayload succeeds at ReadCurrent but StateVersions.Download(url) fails: network egress blocked to the state-storage host, the presigned URL expired, or the object-storage endpoint returned an error.

Common situations: Restrictive egress proxies that permit the TFE API hostname but block the state-storage hostname, a large state over a flaky link, or an expired presigned URL after a long delay.

Related errors


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