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
- Pull the last known-good state from TFC (`terraform state pull`) and compare against the bytes being pushed to find where corruption begins.
- If the local statefile on disk is corrupt, restore from backup or from the remote version before retrying.
- Re-run the operation that produced the state to regenerate it cleanly rather than pushing the corrupt copy.
- 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
- Never hand-edit state JSON; use `terraform state` subcommands and let Terraform serialize.
- Keep backups of state before any migration so a corrupt local copy can be restored.
- Validate state with `terraform state pull`/`terraform validate` after transforms.
- Report reproducible parse failures on stock plan/apply as upstream bugs.
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
- must be eight hexadecimal digits
- blob metadata %q was empty
- failed to open file at %v: checksum mismatch, %s != %s
- error uploading state in compatibility mode: %v
- error uploading state: %v
AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07).
Data as JSON: /api/errors/50d5cc0e89414a77.
Report an issue: GitHub.