hashicorp/terraform · error

error reading state

Error message

error reading state: %s

What it means

First step of remoteClient.Put: parse the raw bytes Terraform hands it into a statefile.File. This is local parsing, not a network call. Failure means the bytes are not a recognizable Terraform state format — corruption or a version the parser can't read.

Solutions

  1. Inspect the state bytes: confirm it's JSON starting with {"version":...,"terraform_version":...}.
  2. Use a Terraform version that supports the state schema version in the file (check the 'version' field).
  3. Restore state from the last good TFC/TFE state version snapshot if locally corrupted.
  4. Avoid writing/pushing raw bytes from sources other than `terraform state pull`/`push`.
Defensive patterns

Strategy: validation

Validate before calling

// Validate bytes are JSON state before pushing
var head struct{ Version int `json:"version"` }
if err := json.Unmarshal(state, &head); err != nil { return fmt.Errorf("not JSON state: %w", err) }

Type guard

func looksLikeJSONState(b []byte) bool {
    var h struct{ Version int `json:"version"`; TerraformVersion string `json:"terraform_version"` }
    return json.Unmarshal(b, &h) == nil && h.Version > 0
}

Prevention

When it happens

Trigger: statefile.Read returns an error: the byte slice isn't valid JSON state (truncated, binary, plain text), the state 'version' field is higher than this build supports, or magic header/lineage fields are malformed.

Common situations: State was hand-edited or partially overwritten; downgrading Terraform across a state-format bump; a non-state file (e.g. plan output) was pointed at the state path; concurrent writers corrupted the in-memory buffer.

Related errors


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

Appendix: source

Thrown at internal/backend/remote/backend_state.go:117

	// Create the new state.
	_, err := r.client.StateVersions.Create(ctx, r.workspace.ID, options)
	if err != nil {
		r.stateUploadErr = true
		return fmt.Errorf("error uploading state in compatibility mode: %v", err)
	}
	return err
}

// Put the remote state.
func (r *remoteClient) Put(state []byte) tfdiags.Diagnostics {
	var diags tfdiags.Diagnostics
	ctx := context.Background()

	// Read the raw state into a Terraform state.
	stateFile, err := statefile.Read(bytes.NewReader(state))
	if err != nil {
		return diags.Append(fmt.Errorf("error reading state: %s", err))
	}

	ov, err := jsonstate.MarshalOutputs(stateFile.State.RootOutputValues)
	if err != nil {
		return diags.Append(fmt.Errorf("error reading output values: %s", err))
	}
	o, err := json.Marshal(ov)
	if err != nil {
		return diags.Append(fmt.Errorf("error converting output values to json: %s", err))
	}

	options := tfe.StateVersionUploadOptions{
		StateVersionCreateOptions: tfe.StateVersionCreateOptions{
			Lineage:          tfe.String(stateFile.Lineage),
			Serial:           tfe.Int64(int64(stateFile.Serial)),
			MD5:              tfe.String(fmt.Sprintf("%x", md5.Sum(state))),
			Force:            tfe.Bool(r.forcePush),
			JSONStateOutputs: tfe.String(base64.StdEncoding.EncodeToString(o)),

View on GitHub (pinned to d32a084675)