opentofu/opentofu · error

error finding remote workspace: %w

Error message

error finding remote workspace: %w

What it means

Appended by Cloud.LocalRun (internal/cloud/backend_context.go:109) when b.getRemoteWorkspaceID fails while resolving the opaque workspace ID needed to list workspace variables (only on the non-AllowUnsetVariables path). getRemoteWorkspaceID performs a Workspaces.Read, so this wraps the same failures as fetchWorkspace: 404 (missing workspace or invisible to token), auth, network.

Source

Thrown at internal/cloud/backend_context.go:109

	diags = diags.Append(configDiags)
	if configDiags.HasErrors() {
		return nil, nil, diags
	}
	ret.Config = config

	if op.AllowUnsetVariables {
		// If we're not going to use the variables in an operation we'll be
		// more lax about them, stubbing out any unset ones as unknown.
		// This gives us enough information to produce a consistent context,
		// but not enough information to run a real operation (plan, apply, etc)
		ret.PlanOpts.SetVariables = stubAllVariables(op.Variables, config.Module.Variables)
	} else {
		// The underlying API expects us to use the opaque workspace id to request
		// variables, so we'll need to look that up using our organization name
		// and workspace name.
		remoteWorkspaceID, err := b.getRemoteWorkspaceID(context.Background(), op.Workspace)
		if err != nil {
			diags = diags.Append(fmt.Errorf("error finding remote workspace: %w", err))
			return nil, nil, diags
		}
		w, err := b.fetchWorkspace(context.Background(), b.organization, op.Workspace)
		if err != nil {
			diags = diags.Append(fmt.Errorf("error loading workspace: %w", err))
			return nil, nil, diags
		}

		if isLocalExecutionMode(w.ExecutionMode) {
			log.Printf("[TRACE] skipping retrieving variables from workspace %s/%s (%s), workspace is in Local Execution mode", remoteWorkspaceName, b.organization, remoteWorkspaceID)
		} else {
			log.Printf("[TRACE] cloud: retrieving variables from workspace %s/%s (%s)", remoteWorkspaceName, b.organization, remoteWorkspaceID)
			tfeVariables, err := b.client.Variables.List(context.Background(), remoteWorkspaceID, nil)
			if err != nil && err != tfe.ErrResourceNotFound {
				diags = diags.Append(fmt.Errorf("error loading variables: %w", err))
				return nil, nil, diags
			}

View on GitHub (pinned to 3561785c48)

Solutions

  1. Verify the workspace still exists and the token can read it (same checks as the 'workspace not found' error, backend.go:1126).
  2. Re-run; transient mid-run 404s from eventual consistency usually clear.
  3. Correct workspace selection (tags mapping, TF_WORKSPACE) before planning.
Defensive patterns

Strategy: type-guard

Validate before calling

// Confirm workspace resolvable before LocalRun's variable phase
if _, err := client.Workspaces.Read(ctx, org, op.Workspace); err != nil {
    return fmt.Errorf("workspace %s unreadable (%w) - fix name/token first", op.Workspace, err)
}

Type guard

func isRemoteWorkspaceLookupFailure(err error) bool {
    return strings.HasPrefix(err.Error(), "error finding remote workspace")
}

Try / catch

_, _, diags := b.LocalRun(ctx, stopCtx, op)
if isRemoteWorkspaceLookupFailure(diags.Err()) {
    // wrapped cause is a fetchWorkspace-style error: 404 vs auth vs network decides the fix
}

Prevention

When it happens

Trigger: Workspaces.Read during variable resolution returns tfe.ErrResourceNotFound, 401/403, or transport errors - e.g. workspace deleted between the earlier StateMgr step and here, or token without read access to that workspace.

Common situations: Workspace renamed/deleted mid-pipeline; wrong TF_WORKSPACE for the mapped environment; token team removed from the workspace between runs.

Related errors


AI-assisted analysis of opentofu/opentofu@3561785c48 (2026-08-15). Data as JSON: /api/errors/3270f407a070ddc6. Report an issue: GitHub.