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

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.

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 c9def3e214)

Solutions

  1. Download Terraform v0.9.x and run 'terraform init' once in the directory to perform the legacy-to-backend upgrade.
  2. If the legacy state is not worth migrating, remove .terraform/ and reconfigure the backend fresh with your current Terraform.
  3. If the legacy remote state must be preserved, export it with the old v0.8/v0.9 tooling before upgrading.

Example fix

// before (modern terraform)
$ terraform init
Error: this working directory uses legacy remote state and so must first be upgraded using Terraform v0.9

// after
$ tfenv use 0.9.11   # one-time upgrade
$ terraform init
# then return to modern terraform:
$ tfenv use 1.10.0
$ terraform init
Defensive patterns

Strategy: validation

Validate before calling

// Detect the legacy 'remote' shape before relying on the parse result.
func isLegacyRemoteState(src []byte) bool {
    var probe struct {
        Backend *json.RawMessage `json:"backend"`
        Remote  *json.RawMessage `json:"remote"`
    }
    _ = json.Unmarshal(src, &probe)
    return probe.Backend == nil && probe.Remote != nil
}

Type guard

null

Try / catch

null

Prevention

When it happens

Trigger: ParseBackendStateFile reaches backend_state.go:103 because Backend == nil and Remote != nil after a successful parse.

Common situations: 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.

Related errors


AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07). Data as JSON: /api/errors/9ea9eed9577140c9. Report an issue: GitHub.