Skip to content

Confusing behaviour when applying a plan against a workspace that doesn't match the plan #37954

@SarahFrench

Description

@SarahFrench

Terraform Version

% terraform version
Terraform v1.15.0-dev
on darwin_arm64

Terraform Configuration Files

Any configuration can be used to reproduce this issue.

Debug Output

N/A

Expected Behavior

Terraform should raise an error, or at least warning, if a terraform apply command tries to apply a plan against a workspace that doesn't match the workspace that the plan was prepared against. An explicit message saying something like 'the plan expected workspace A but the working directory currently has workspace B selected' would help users figure out what's gone wrong in their workflow.

Actual Behavior

Assume that a plan was raised against workspace A and a user tries to apply it against workspace B.

The actual behaviour varies depending on the type of plan and what state already exists for workspace B.

  1. If the plan is create-only, starting from a position of empty state, and workspace B has no state yet then the apply will complete successfully
  2. If the plan is create-only, starting from a position of empty state, and workspace B has a prior state then the apply will fail with error Saved plan is stale.
  3. If the plan is changing existing resources, i.e. planned using prior state in workspace A, and workspace B has no prior state then the apply will fail with a different state lineage error.

In case 2 & 3 the apply stops before making any changes to state, however the error messages don't clearly point out that mismatched workspaces are the underlying cause.

In case 1 users will find that the new state file is persisted in a different location than they expected. The output from the apply command doesn't say which workspace the apply affected, so the user might not notice the issue immediately.

Steps to Reproduce

See #37919 for E2E tests reproducing the 3 cases above.

To reproduce the 3 cases I described above:

Case 1

  • terraform init
  • While default workspace selected, run terraform plan -out=tfplan to create a plan file
  • Run terraform workspace create foobar to create and select a custom workspace
  • Run terraform apply tfplan to apply the plan file
  • See that new state is created for the custom workspace

Case 2

  • terraform init
  • Run terraform workspace create foobar to create and select a custom workspace
  • terraform apply to create some state in the custom workspace
  • terraform workspace select default to change workspace to the empty default workspace
  • Run terraform plan -out=tfplan to create a plan file.
    • This plan describes creating resources from an empty state starting point
  • terraform workspace select foobar to change to the custom workspace again
  • Run terraform apply tfplan to apply the plan file
  • There should be an error reporting the plan is stale.

Case 3

  • terraform init
  • terraform apply to create state in the default workspace
  • Change the configuration so that there's a diff when plan is run next
  • Run terraform plan -out=tfplan to create a plan file.
    • The plan will describe changing existing resources
  • Run terraform workspace create foobar to create and select a custom workspace
  • Run terraform apply tfplan to apply the plan file
  • There should be an error reporting that there's a mismatch of state lineage.

Additional Context

The BackendForLocalPlan method has a godoc comment that suggests that it asserts the plan's workspace matches the current workspace:

// The current workspace name is also stored as part of the plan, and so this
// method will check that it matches the currently-selected workspace name
// and produce error diagnostics if not.

It doesn't look like this was implemented at the time (see commit) that method was written.

This work has also touched the BackendForLocalPlan method #25262 but this just validates that the current workspace name is valid. It doesn't include comparison to the value in the plan file.

I'm going to open a PR adding that assertion, but I'll also ask around to see if this is something that was purposefully dropped in the past. Currently Terraform does protect against any existing state being affected in these scenarios, and there might be considerations around HCP Terraform that make this assertion trickier to implement smoothly for all backends in use.

References

Generative AI / LLM assisted development?

No response

Metadata

Metadata

Assignees

Labels

bugnewnew issue not yet triaged

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions