hashicorp/terraform · error
this working directory uses legacy remote state and so must…
Error message
this working directory uses legacy remote state and so must first be upgraded using Terraform v0.9
What it means
ParseBackendStateFile decoded the file successfully and found a non-nil `remote` block but no `backend` block. That shape is the pre-0.9 legacy remote-state format, which the current binary cannot use directly — the user must upgrade it with Terraform v0.9 first (which converts `remote` to `backend`).
Solutions
- Run `terraform init` once with Terraform v0.9.x in this workspace to perform the legacy-to-backend migration, then switch to a modern binary.
- If v0.9 is unavailable, discard the legacy file (rm .terraform/terraform.tfstate) and configure a fresh backend block + `terraform init`.
- Migrate state to a remote backend (S3, etc.) from v0.9 first, then continue on the current version.
Example fix
# step 1 — upgrade the legacy file with terraform 0.9 terraform0.9 init # step 2 — continue with modern terraform terraform init
Defensive patterns
Strategy: validation
Validate before calling
// detect legacy remote shape up front and steer the user to the upgrade path
var probe struct {
Backend *json.RawMessage `json:"backend"`
Remote *json.RawMessage `json:"remote"`
}
_ = json.Unmarshal(src, &probe)
if probe.Backend == nil && probe.Remote != nil {
return nil, errors.New("legacy remote state detected; run `terraform init` under v0.9.x to migrate, then re-init on the current version")
} Prevention
- When reviving old workspaces, run them once on v0.9 before going modern.
- Prefer remote backends (S3, etc.) over legacy remote state.
When it happens
Trigger: Opening a workspace last touched by Terraform v0.8.x or earlier, where state was configured via the legacy `remote` subcommand rather than a backend block.
Common situations: Decades-old infrastructure workspace never migrated, archived project resurrected with a modern Terraform, training/lab environments frozen at v0.8.
Related errors
- encountered a malformed backend state file that contains…
- encountered a malformed backend state file with a…
- Error asking for state migration action
- Error copying state from the previous %[1]q %[2]s to the…
- Error creating temporary directory
AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11).
Data as JSON: /api/errors/9ea9eed9577140c9.
Report an issue: GitHub.
Appendix: source
Thrown at internal/command/workdir/backend_state.go:108
return nil, fmt.Errorf("invalid syntax: no format version number")
}
if versionSniff.Version != 3 {
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)
}
// If we get here then we can be sure that this file at least _thinks_
// it's format version 3.
var stateFile BackendStateFile
err = json.Unmarshal(src, &stateFile)
if err != nil {
return nil, fmt.Errorf("invalid syntax: %w", err)
}
if stateFile.Backend == nil && stateFile.Remote != nil {
// It's very unlikely to get here, but one way it could happen is
// if this working directory was most recently used with Terraform v0.8
// or earlier, which didn't yet include the concept of backends.
// This error message assumes that's the case.
return nil, fmt.Errorf("this working directory uses legacy remote state and so must first be upgraded using Terraform v0.9")
}
if stateFile.Backend != nil && stateFile.StateStore != nil {
return nil, fmt.Errorf("encountered a malformed backend state file that contains state for both a 'backend' and a 'state_store' block")
}
if stateFile.StateStore != nil && stateFile.StateStore.ProviderSupplyMode == "" {
// Check for this, as lacking this data can cause problems later when an empty provider version
// is encountered. This error will make debugging much easier.
return nil, fmt.Errorf("encountered a malformed backend state file with a 'state_store' block that is missing the required 'provider_supply_mode' property")
}
return &stateFile, nil
}
func EncodeBackendStateFile(f *BackendStateFile) ([]byte, error) {
f.Version = 3 // we only support version 3
f.TFVersion = version.SemVer.String()
switch {View on GitHub (pinned to d32a084675)