hashicorp/terraform · error

invalid syntax: no format version number

Error message

invalid syntax: no format version number

What it means

ParseBackendStateFile successfully parsed JSON but the top-level `version` field was 0 (the zero value), which means the field is missing entirely or explicitly null. Version 0 is impossible for JSON state (snapshot version 0 was gob-encoded binary), so this is treated as a malformed/unsupported file.

Solutions

  1. Confirm the file is meant to be a Terraform backend state file (it may have been overwritten by another tool).
  2. Delete the bogus file and `terraform init` to recreate it from the backend block.
  3. If migrating from another tool, write a proper backend "<type>" {} block and init instead.

Example fix

# before — .terraform/terraform.tfstate contains just {"backend":{...}}

# after — let terraform own the file
rm .terraform/terraform.tfstate
terraform init
Defensive patterns

Strategy: validation

Validate before calling

// pre-flight: reject files missing the version field up front
var sniff struct{ Version int `json:"version"` }
_ = json.Unmarshal(src, &sniff)
if sniff.Version == 0 {
    return nil, errors.New("backend state file lacks a version field; regenerate with `terraform init`")
}

Type guard

func hasVersionField(src []byte) bool {
    var s struct{ Version int `json:"version"` }
    _ = json.Unmarshal(src, &s)
    return s.Version != 0
}

Prevention

When it happens

Trigger: A .terraform/terraform.tfstate file whose JSON is valid but lacks a numeric `version` key, e.g. a hand-rolled stub, a different tool's JSON, or a backend state produced by a fork that omits the version field.

Common situations: User-generated or third-party tool wrote a JSON file in .terraform/ without the schema Terraform expects; partial merge/clobber of the file.

Related errors


AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11). Data as JSON: /api/errors/a0295393b53a78ba. Report an issue: GitHub.

Appendix: source

Thrown at internal/command/workdir/backend_state.go:90

	// the format, we'll do a first pass of decoding just the "version"
	// property, and then decode the rest only if we find the version number
	// that we're expecting.
	type VersionSniff struct {
		Version   int    `json:"version"`
		TFVersion string `json:"terraform_version,omitempty"`
	}
	var versionSniff VersionSniff
	err := json.Unmarshal(src, &versionSniff)
	if err != nil {
		return nil, fmt.Errorf("invalid syntax: %w", err)
	}
	if versionSniff.Version == 0 {
		// This could either mean that it's explicitly "version": 0 or that
		// the version property is missing. We'll assume the latter here
		// because state snapshot version 0 was an encoding/gob binary format
		// rather than a JSON format and so it would be very weird for
		// that to show up in a JSON file.
		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")

View on GitHub (pinned to d32a084675)