{"record":{"id":"79d76f703be7183f","repo":"hashicorp/terraform","slug":"remote-workspace-terraform-version-q-does-not-mat-79d76f","errorCode":null,"errorMessage":"Remote workspace Terraform version %q does not match local Terraform version %q","messagePattern":"Remote workspace Terraform version %q does not match local Terraform version %q","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/cloud/backend.go","lineNumber":874,"sourceCode":"\t\t\t}\n\t\t\t_, err = b.client.Workspaces.AddTagBindings(context.Background(), workspace.ID, options)\n\t\t}\n\n\t\tif err != nil {\n\t\t\treturn nil, diags.Append(fmt.Errorf(\"error updating workspace %q tags: %w\", name, err))\n\t\t}\n\t}\n\n\t// This is a fallback error check. Most code paths should use other\n\t// mechanisms to check the version, then set the ignoreVersionConflict\n\t// field to true. This check is only in place to ensure that we don't\n\t// accidentally upgrade state with a new code path, and the version check\n\t// logic is coarser and simpler.\n\tif !b.ignoreVersionConflict {\n\t\t// Explicitly ignore the pseudo-version \"latest\" here, as it will cause\n\t\t// plan and apply to always fail.\n\t\tif remoteTFVersion != tfversion.String() && remoteTFVersion != \"latest\" {\n\t\t\treturn nil, diags.Append(fmt.Errorf(\"Remote workspace Terraform version %q does not match local Terraform version %q\", remoteTFVersion, tfversion.String()))\n\t\t}\n\t}\n\n\treturn &State{tfeClient: b.client, organization: b.Organization, workspace: workspace, enableIntermediateSnapshots: false}, diags\n}\n\n// Operation implements backendrun.OperationsBackend.\nfunc (b *Cloud) Operation(ctx context.Context, op *backendrun.Operation) (*backendrun.RunningOperation, error) {\n\t// Retrieve the workspace for this operation.\n\tw, err := b.fetchWorkspace(ctx, b.Organization, op.Workspace)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Terraform remote version conflicts are not a concern for operations. We\n\t// are in one of three states:\n\t//\n\t// - Running remotely, in which case the local version is irrelevant;","sourceCodeStart":856,"sourceCodeEnd":892,"githubUrl":"https://github.com/hashicorp/terraform/blob/c9def3e214014c1188faabfc4a5bde5095139765/internal/cloud/backend.go#L856-L892","documentation":"A safety fallback guard at backend.go:870-876 that aborts state access when the remote workspace's recorded Terraform version differs from the local terraform binary version and ignoreVersionConflict has not been set. It exists to prevent state from being written by a mismatched engine version, which could corrupt or upgrade the state format unexpectedly. The pseudo-version \"latest\" is explicitly skipped so it never trips this check.","triggerScenarios":"Calling StateMgr/LocalRun when remoteTFVersion != tfversion.String() and remoteTFVersion != \"latest\" and b.ignoreVersionConflict == false. Happens when a workspace is pinned to e.g. 1.6.x but the local binary is 1.7.x (or vice-versa).","commonSituations":"Upgrading the local Terraform CLI without updating the workspace's Terraform Version setting in HCP/TFE. Downgrading locally for debugging while the workspace stays on a newer version. CI runners auto-pulling latest terraform while workspaces are pinned. The Operation() path (backend.go:897) calls IgnoreVersionConflict(), so this mainly bites state-only access (LocalRun / StateMgr) before an operation.","solutions":["Align the versions: update the workspace's Terraform Version in HCP Terraform / TFE UI to match your local binary, OR downgrade/upgrade the local binary to match the workspace.","If the mismatch is intentional (e.g. worker forcing local ops), call IgnoreVersionConflict() before accessing state, or run through the Operation() path which does this automatically.","Set the workspace version to 'latest' so the check is bypassed (note: not recommended for apply/plan per the comment at backend.go:871-872)."],"exampleFix":"// before: local 1.7.x, workspace pinned to 1.6.x -> error\n// fix A: update workspace version in UI to 1.7.x\n// fix B: explicit ignore when forcing local\n// (code path) b.IgnoreVersionConflict() is invoked by Operation();\n// for direct StateMgr use ensure versions match.","handlingStrategy":"validation","validationCode":"// Compare local vs remote version before any state access.\nfunc versionsAligned(local, remote string) bool {\n    return remote == \"latest\" || remote == local\n}\n// Call b.IgnoreVersionConflict() instead if mismatch is intentional,\n// or update the workspace version in HCP/TFE to match runtime.Version().","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Pin workspace Terraform Version to the exact CLI version used in CI.","In CI, install the same Terraform version the workspace is configured for.","Use Operation() paths (plan/apply) which auto-ignore version conflicts rather than direct StateMgr."],"tags":["terraform","version-mismatch","state","cloud-backend","configuration"],"analyzedSha":"c9def3e214014c1188faabfc4a5bde5095139765","analyzedAt":"2026-08-07T15:39:49.278Z","schemaVersion":2},"datasetVersion":"2026-08-07T20:17:04.800Z"}