hashicorp/terraform · error

Error downloading state: %v

Error message

Error downloading state: %v

What it means

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.

Source

Thrown at internal/backend/remote/backend_state.go:67

var _ Fatal = errorUnlockFailed{}

// Get the remote state.
func (r *remoteClient) Get() (*remote.Payload, tfdiags.Diagnostics) {
	var diags tfdiags.Diagnostics
	ctx := context.Background()

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

	state, err := r.client.StateVersions.Download(ctx, sv.DownloadURL)
	if err != nil {
		return nil, diags.Append(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
}

func (r *remoteClient) uploadStateFallback(ctx context.Context, stateFile *statefile.File, state []byte, jsonStateOutputs []byte) error {
	options := tfe.StateVersionCreateOptions{

View on GitHub (pinned to c9def3e214)

Solutions

  1. Retry the command immediately — a fresh ReadCurrent yields a fresh signed DownloadURL.
  2. Allowlist the object-storage egress domain (e.g. *.amazonaws.com) in firewall/proxy alongside the TFC API host.
  3. Reduce state size / split workspaces if downloads repeatedly hit proxy body-size or timeout limits.
  4. Check the TFC status page for object-storage incidents.

Example fix

// before: pre-signed URL expired in a slow CI step
$ terraform plan
Error: Error downloading state: 403 Forbidden

// after: retry issues a fresh signed URL
$ terraform plan   # succeeds on retry
Defensive patterns

Strategy: retry

Validate before calling

// Confirm the workspace's current state version has a usable download URL preflight.
sv, err := r.client.StateVersions.ReadCurrent(ctx, r.workspace.ID)
if err != nil { return err }
if sv.DownloadURL == "" { return errors.New("no download URL available; retry ReadCurrent") }

Try / catch

// Re-fetch the (freshly signed) state version then retry the download once.
state, err := r.client.StateVersions.Download(ctx, sv.DownloadURL)
if err != nil {
    sv, rerr := r.client.StateVersions.ReadCurrent(ctx, r.workspace.ID)
    if rerr == nil {
        state, err = r.client.StateVersions.Download(ctx, sv.DownloadURL)
    }
}
if err != nil { return nil, diags.Append(fmt.Errorf("Error downloading state: %v", err)) }

Prevention

When it happens

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

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

Related errors


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