hashicorp/terraform · error

error reading state: %s

Error message

error reading state: %s

What it means

Emitted by remoteClient.Put (backend_state.go:115-118) when statefile.Read cannot parse the bytes about to be uploaded as a Terraform state file. Put receives already-serialized state from the local statemgr; if those bytes are not a valid state JSON document, reading fails before any output marshaling or upload happens.

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

Solutions

  1. Pull the last known-good state from TFC (`terraform state pull`) and compare against the bytes being pushed to find where corruption begins.
  2. If the local statefile on disk is corrupt, restore from backup or from the remote version before retrying.
  3. Re-run the operation that produced the state to regenerate it cleanly rather than pushing the corrupt copy.
  4. Report an upstream bug if a stock `terraform plan/apply` is the producer — this path should never see unparseable bytes.

Example fix

// before: corrupt local state
$ terraform apply
Error: error reading state: invalid character 'x' looking for beginning of value

// after: restore good state then apply
$ terraform state pull > good.tfstate
$ terraform push good.tfstate && terraform apply
Defensive patterns

Strategy: validation

Validate before calling

// Sanity-check the state bytes parse before handing them to Put.
if _, err := statefile.Read(bytes.NewReader(state)); err != nil {
    return fmt.Errorf("refusing to upload unparseable state: %w", err)
}

Prevention

When it happens

Trigger: The in-memory state bytes passed to Put are truncated, not valid JSON, use an unrecognized state format version, or are otherwise corrupt. This is a precondition failure: the data handed to the remote client was already malformed upstream.

Common situations: State was produced/transformed by a buggy process or manual edit; a partial write left a truncated state file; a migration tool emitted a state schema version this build doesn't understand; disk/memory corruption.

Related errors


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