Skip to content

Local state: apply reports success but writes no state when the state file can't be created and -lock=false #39409

Open

Description

@555aaditya

Terraform Version

Terraform v1.18.0-dev
on darwin_arm64

Built from main at 44fcc13 (2026-10-16). The code path involved has not changed since 53cafc5 (2018), so released versions should behave the same way.

Terraform Configuration Files

resource "terraform_data" "example" {
  input = "hello"
}

Debug Output

Relevant lines from TF_LOG=trace (timestamps stripped):

[TRACE] statemgr.Filesystem: preparing to manage state snapshots at ro/out.tfstate
[DEBUG] State storage *statemgr.Filesystem declined to persist a state snapshot
[TRACE] statemgr.Filesystem: reading initial snapshot from terraform.tfstate
[TRACE] statemgr.Filesystem: snapshot file has nil snapshot, but that's okay
[TRACE] statemgr.Filesystem: read nil snapshot
[TRACE] statemgr.Filesystem: preparing to manage state snapshots at ro/out.tfstate
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
State path: ro/out.tfstate

Expected Behavior

When the local state file can't be created or opened, terraform apply should fail with an error. Terraform's existing recovery path should then run: it reports "Failed to persist state to backend" and writes errored.tfstate. This is what already happens when locking is enabled, because Lock() calls the same createStateFiles() and returns its error.

Actual Behavior

With -lock=false, the apply creates the resource, prints Apply complete! and State path: ro/out.tfstate, and exits 0, but no state file is written anywhere. The created resource is now untracked, and nothing tells the user.

The cause is in internal/states/statemgr/filesystem.go, in (*Filesystem).writeState:

if s.stateFileOut == nil {
    if err := s.createStateFiles(); err != nil {
        return nil   // error is discarded
    }
}

With locking enabled, Lock() calls createStateFiles() first and handles the error correctly. Without a lock, writeState is the first caller, so the error is swallowed and the method reports success.

Steps to Reproduce

mkdir repro && cd repro
cat > main.tf <<'EOF'
resource "terraform_data" "example" {
  input = "hello"
}
EOF
mkdir ro && chmod 0555 ro
terraform init
terraform apply -auto-approve -lock=false -state-out=ro/out.tfstate
echo "exit=$?"     # exit=0, "Apply complete!"
ls ro              # empty: no state was written

For comparison, the same command without -lock=false fails correctly with Error acquiring the state lock ... open ro/out.tfstate: permission denied.

Additional Context

I tried the one-line change return nil → return err locally. The repro above then fails with Error: Failed to persist state to backend and writes errored.tfstate to the working directory, which is the intended recovery behaviour.

If the team agrees this is the right fix, I'd be happy to open a PR with it, plus a regression test in internal/states/statemgr/filesystem_test.go.

References

Generative AI / LLM assisted development?

Claude Code (Anthropic) was used to find this code path, reproduce it, and draft this report.

Activity

  1. self-assigned this
    on Oct 19, 2026
  2. added
    newnew issue not yet triaged
    on Oct 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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