{"record":{"id":"9ea9eed9577140c9","repo":"hashicorp/terraform","slug":"this-working-directory-uses-legacy-remote-state-an","errorCode":null,"errorMessage":"this working directory uses legacy remote state and so must first be upgraded using Terraform v0.9","messagePattern":"this working directory uses legacy remote state and so must first be upgraded using Terraform v0\\.9","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/command/workdir/backend_state.go","lineNumber":108,"sourceCode":"\t\treturn nil, fmt.Errorf(\"invalid syntax: no format version number\")\n\t}\n\tif versionSniff.Version != 3 {\n\t\treturn 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)\n\t}\n\n\t// If we get here then we can be sure that this file at least _thinks_\n\t// it's format version 3.\n\tvar stateFile BackendStateFile\n\terr = json.Unmarshal(src, &stateFile)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid syntax: %w\", err)\n\t}\n\tif stateFile.Backend == nil && stateFile.Remote != nil {\n\t\t// It's very unlikely to get here, but one way it could happen is\n\t\t// if this working directory was most recently used with Terraform v0.8\n\t\t// or earlier, which didn't yet include the concept of backends.\n\t\t// This error message assumes that's the case.\n\t\treturn nil, fmt.Errorf(\"this working directory uses legacy remote state and so must first be upgraded using Terraform v0.9\")\n\t}\n\tif stateFile.Backend != nil && stateFile.StateStore != nil {\n\t\treturn nil, fmt.Errorf(\"encountered a malformed backend state file that contains state for both a 'backend' and a 'state_store' block\")\n\t}\n\tif stateFile.StateStore != nil && stateFile.StateStore.ProviderSupplyMode == \"\" {\n\t\t// Check for this, as lacking this data can cause problems later when an empty provider version\n\t\t// is encountered. This error will make debugging much easier.\n\t\treturn nil, fmt.Errorf(\"encountered a malformed backend state file with a 'state_store' block that is missing the required 'provider_supply_mode' property\")\n\t}\n\n\treturn &stateFile, nil\n}\n\nfunc EncodeBackendStateFile(f *BackendStateFile) ([]byte, error) {\n\tf.Version = 3 // we only support version 3\n\tf.TFVersion = version.SemVer.String()\n\n\tswitch {","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/hashicorp/terraform/blob/c9def3e214014c1188faabfc4a5bde5095139765/internal/command/workdir/backend_state.go#L90-L126","documentation":"The backend state file has a 'remote' key but no 'backend' key. That shape only existed in Terraform v0.8 and earlier, before the backend concept existed (see the Remote field comment at backend_state.go:42). Modern Terraform cannot read it and requires a one-time upgrade through v0.9, which knew how to migrate legacy remote state into the backend format.","triggerScenarios":"ParseBackendStateFile reaches backend_state.go:103 because Backend == nil and Remote != nil after a successful parse.","commonSituations":"Dusting off an ancient project directory not touched since ~2017; copying old .terraform/ artifacts forward into a modern Terraform; tutorial repos archived with v0.8-era state.","solutions":["Download Terraform v0.9.x and run 'terraform init' once in the directory to perform the legacy-to-backend upgrade.","If the legacy state is not worth migrating, remove .terraform/ and reconfigure the backend fresh with your current Terraform.","If the legacy remote state must be preserved, export it with the old v0.8/v0.9 tooling before upgrading."],"exampleFix":"// before (modern terraform)\n$ terraform init\nError: this working directory uses legacy remote state and so must first be upgraded using Terraform v0.9\n\n// after\n$ tfenv use 0.9.11   # one-time upgrade\n$ terraform init\n# then return to modern terraform:\n$ tfenv use 1.10.0\n$ terraform init","handlingStrategy":"validation","validationCode":"// Detect the legacy 'remote' shape before relying on the parse result.\nfunc isLegacyRemoteState(src []byte) bool {\n    var probe struct {\n        Backend *json.RawMessage `json:\"backend\"`\n        Remote  *json.RawMessage `json:\"remote\"`\n    }\n    _ = json.Unmarshal(src, &probe)\n    return probe.Backend == nil && probe.Remote != nil\n}","typeGuard":"null","tryCatchPattern":"null","preventionTips":["When resurrecting very old projects, run a one-time v0.9 init before using modern Terraform.","Document the legacy-state upgrade step in any migration runbook.","Don't copy .terraform/ artifacts between unrelated project directories."],"tags":["terraform","legacy","migration","state","workdir"],"analyzedSha":"c9def3e214014c1188faabfc4a5bde5095139765","analyzedAt":"2026-08-07T15:39:49.278Z","schemaVersion":2},"datasetVersion":"2026-08-07T21:17:07.882Z"}