hashicorp/terraform · error

error loading workspace

Error message

error loading workspace: %w

What it means

Thrown by Cloud.FetchVariables after b.fetchWorkspace(ctx, b.Organization, workspace) returns a non-nil error. The backend needs full workspace metadata (not just the ID that getRemoteWorkspaceID already retrieved) to inspect ExecutionMode before deciding whether to fetch variables. The wrapped error carries the underlying cause from the TFE/HCP API client.

Solutions

  1. Verify the workspace name and organization in your cloud backend config match HCP Terraform exactly (case-sensitive).
  2. Run `terraform login` again or rotate the token; confirm the token's team has read access on the workspace.
  3. Re-run: fetchWorkspace is a plain read, so transient API/network errors often clear on retry.
  4. Inspect the wrapped `%w` cause: a 404 points to naming, a 401/403 to auth, a timeout to network.
  5. If using self-hosted TFE, check the API health and that the agent/runner can reach it.

Example fix

// before
workspaces {
  name = "my-app-prod"
  organization = "MyOrg"
}
// after - fix casing to match HCP Terraform exactly
workspaces {
  name = "my-app-prod"
  organization = "myorg"
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Before calling operations that trigger FetchVariables, verify workspace access.
func workspaceReadable(b *Cloud, ctx context.Context, org, name string) error {
    _, err := b.fetchWorkspace(ctx, org, name)
    return err
}

Try / catch

// diags is the idiomatic Go pattern here; FetchVariables returns diags.
diags := backend.FetchVariables(ctx, ws)
if diags.HasErrors() {
    // surface diags to the user; do not proceed
}

Prevention

When it happens

Trigger: fetchWorkspace issues a TFE Workspaces.Read request; it fails on a 404 (wrong org/workspace name), 401/403 (token lacks read access or `terraform login` not done), network/transport error, or a 5xx from the TFE instance. The earlier getRemoteWorkspaceID succeeded (so the workspace exists by ID lookup), making this most often a transient API hiccup, a permissions race, or an API-version skew between the two read calls.

Common situations: Workspace name casing mismatch between workspaces block and the real HCP workspace; token scoped to a team without workspace read; self-hosted TFE behind a flaky proxy; org name typo in the cloud backend config; an API call retry where the second read hits a different rate-limit window.

Related errors


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

Appendix: source

Thrown at internal/cloud/backend_context.go:196

	}

	return remoteWorkspace.ID, nil
}

// FetchVariables implements backendrun.ConstVariableSupplier by retrieving
// Terraform variables from the HCP Terraform or Terraform Enterprise workspace.
func (b *Cloud) FetchVariables(ctx context.Context, workspace string) (map[string]arguments.UnparsedVariableValue, tfdiags.Diagnostics) {
	var diags tfdiags.Diagnostics

	remoteWorkspaceID, err := b.getRemoteWorkspaceID(ctx, workspace)
	if err != nil {
		diags = diags.Append(fmt.Errorf("error finding remote workspace: %w", err))
		return nil, diags
	}

	w, err := b.fetchWorkspace(ctx, b.Organization, workspace)
	if err != nil {
		diags = diags.Append(fmt.Errorf("error loading workspace: %w", err))
		return nil, diags
	}

	if isLocalExecutionMode(w.ExecutionMode) {
		log.Printf("[TRACE] cloud: skipping variable fetch for workspace %s/%s (%s), workspace is in Local Execution mode", b.getRemoteWorkspaceName(workspace), b.Organization, remoteWorkspaceID)
		return nil, nil
	}

	log.Printf("[TRACE] cloud: retrieving variables from workspace %s/%s (%s)", b.getRemoteWorkspaceName(workspace), b.Organization, remoteWorkspaceID)
	tfeVariables, err := b.client.Variables.ListAll(ctx, remoteWorkspaceID, nil)
	if err != nil && err != tfe.ErrResourceNotFound {
		diags = diags.Append(fmt.Errorf("error loading variables: %w", err))
		return nil, diags
	}

	result := make(map[string]arguments.UnparsedVariableValue)
	if tfeVariables != nil {
		for _, v := range tfeVariables.Items {

View on GitHub (pinned to d32a084675)