From d4e108864ce5b4457b2a54303f67c1c0840a7769 Mon Sep 17 00:00:00 2001 From: Kevin Vu Date: Sat, 13 Dec 2025 03:48:44 -0800 Subject: [PATCH] fix: improve error message for corrupted backend state Fixes #37953 --- .../v1.15/ENHANCEMENTS-20251213-034829.yaml | 5 +++++ internal/command/workdir/backend_state.go | 9 +++++++++ internal/command/workdir/backend_state_test.go | 17 ++++++++++++++--- 3 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 .changes/v1.15/ENHANCEMENTS-20251213-034829.yaml diff --git a/.changes/v1.15/ENHANCEMENTS-20251213-034829.yaml b/.changes/v1.15/ENHANCEMENTS-20251213-034829.yaml new file mode 100644 index 000000000000..0cac80d186b0 --- /dev/null +++ b/.changes/v1.15/ENHANCEMENTS-20251213-034829.yaml @@ -0,0 +1,5 @@ +kind: ENHANCEMENTS +body: 'cli: improve error message when backend state file is corrupted by state data' +time: 2025-12-13T11:50:00.000000+00:00 +custom: + Issue: "37953" diff --git a/internal/command/workdir/backend_state.go b/internal/command/workdir/backend_state.go index 6494353c5239..c7300815f55a 100644 --- a/internal/command/workdir/backend_state.go +++ b/internal/command/workdir/backend_state.go @@ -90,6 +90,15 @@ func ParseBackendStateFile(src []byte) (*BackendStateFile, error) { return nil, fmt.Errorf("invalid syntax: no format version number") } if versionSniff.Version != 3 { + // Check if this looks like a state snapshot file (version 4) + // rather than a backend configuration file. This can happen if + // someone accidentally configures their local backend to store + // state in the .terraform/ directory, overwriting the internal + // backend configuration. Version 4 is the state snapshot format + // and is never used for backend configuration files. + if versionSniff.Version == 4 { + return nil, fmt.Errorf("the backend configuration file appears to contain Terraform state data rather than backend configuration; the .terraform directory may have been corrupted by storing user data there (the .terraform directory is for internal Terraform use only)") + } return nil, fmt.Errorf("unsupported backend state version %d; you may need to use Terraform CLI v%s to work in this directory", versionSniff.Version, versionSniff.TFVersion) } diff --git a/internal/command/workdir/backend_state_test.go b/internal/command/workdir/backend_state_test.go index 1937000bf5cc..9fca9335c7c0 100644 --- a/internal/command/workdir/backend_state_test.go +++ b/internal/command/workdir/backend_state_test.go @@ -34,12 +34,23 @@ func TestParseBackendStateFile(t *testing.T) { }`, WantErr: `unsupported backend state version 2; you may need to use Terraform CLI v0.3.0 to work in this directory`, }, - "newer version": { + "state snapshot file overwrote backend state": { Input: `{ "version": 4, - "terraform_version": "54.23.9" + "terraform_version": "1.14.0" }`, - WantErr: `unsupported backend state version 4; you may need to use Terraform CLI v54.23.9 to work in this directory`, + WantErr: `the backend configuration file appears to contain Terraform state data rather than backend configuration; the .terraform directory may have been corrupted by storing user data there (the .terraform directory is for internal Terraform use only)`, + }, + "state snapshot file with lineage": { + Input: `{ + "version": 4, + "terraform_version": "1.14.0", + "lineage": "abc123-def456", + "serial": 1, + "outputs": {}, + "resources": [] + }`, + WantErr: `the backend configuration file appears to contain Terraform state data rather than backend configuration; the .terraform directory may have been corrupted by storing user data there (the .terraform directory is for internal Terraform use only)`, }, "legacy remote state is active": { Input: `{