hashicorp/terraform · error
failed to write state
Error message
failed to write state: %w
What it means
Thrown by Local.opRefresh after a successful refresh when statemgr.WriteAndPersist(opState, newState, schemas) returns a non-nil error while writing the refreshed state back to disk (or to the wrapped remote backend). The refresh itself succeeded; only persistence failed.
Solutions
- Free up disk space or move TF_DATA_DIR / the state path to a writable volume.
- For remote backends, verify the credentials still have PutObject/storage.objectAdmin and that any state size cap (e.g. S3 object size, DynamoDB lock table) is not exceeded.
- Ensure no other terraform process holds the state lock; rely on the StateLocker rather than disabling it.
- Retry after fixing the underlying I/O issue; the refreshed state is in memory and can be re-persisted on the next run.
Example fix
null
Defensive patterns
Strategy: retry
Validate before calling
// Preflight: writable state target with free space.
func stateWritable(path string) error {
dir := filepath.Dir(path)
var stat unix.Statfs_t
if err := unix.Statfs(dir, &stat); err != nil { return err }
if stat.Bavail*uint64(stat.Bsize) < 1<<20 { return fmt.Errorf("low disk space on %s", dir) }
return os.WriteFile(filepath.Join(dir, ".wprobe"), []byte{}, 0o644)
} Type guard
null
Try / catch
err := statemgr.WriteAndPersist(opState, newState, schemas)
if err != nil {
if isTransient(err) { // retry once after backoff
time.Sleep(500 * time.Millisecond)
err = statemgr.WriteAndPersist(opState, newState, schemas)
}
if err != nil { diags = diags.Append(fmt.Errorf("failed to write state: %w", err)) }
} Prevention
- Ensure the volume holding the state path has free space and is writable.
- For remote backends, confirm the principal still has object-write permission before refresh.
- Never disable the StateLocker to 'work around' lock errors; fix the contention instead.
When it happens
Trigger: WriteAndPersist returns err: the state file path is not writable, the disk is full, a remote backend PUT was rejected (e.g. size limit, lost permissions), or the state lock was released by a competing process. The error is appended to diags and reported via op.ReportResult.
Common situations: Out of disk space on the volume holding terraform.tfstate; a remote backend (S3, GCS, etc.) where the credentials lost write permission between plan and refresh; concurrent terraform runs racing on the same state file; antivirus locking the file on Windows during write.
Related errors
- error loading state
- Failed to load state
- backendDiags.Err()
- could not write lock info for
- error deleting workspace
AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11).
Data as JSON: /api/errors/6faff8e797a2e816.
Report an issue: GitHub.
Appendix: source
Thrown at internal/backend/local/backend_refresh.go:112
newState, refreshDiags = lr.Core.Refresh(lr.Config, lr.InputState, lr.PlanOpts)
log.Printf("[INFO] backend/local: refresh calling Refresh")
}()
if b.opWait(doneCh, stopCtx, cancelCtx, lr.Core, opState, op.View) {
return
}
// Write the resulting state to the running op
runningOp.State = newState
diags = diags.Append(refreshDiags)
if refreshDiags.HasErrors() {
op.ReportResult(runningOp, diags)
return
}
err := statemgr.WriteAndPersist(opState, newState, schemas)
if err != nil {
diags = diags.Append(fmt.Errorf("failed to write state: %w", err))
op.ReportResult(runningOp, diags)
return
}
// Show any remaining warnings before exiting
op.ReportResult(runningOp, diags)
}
View on GitHub (pinned to d32a084675)