hashicorp/terraform · error
error loading state
Error message
error loading state: %w
What it means
Thrown by Local.localRun when b.StateMgr(op.Workspace) returns diagnostics with errors. StateMgr is responsible for creating/opening the state manager for the named workspace, so this error means Terraform could not even obtain a handle to the state before trying to read it.
Solutions
- Inspect the wrapped sDiags.Err() for the real cause (it is included via %w).
- Ensure the state path parent directory exists and is writable: `mkdir -p .terraform/tfstate` and `chmod u+w` on TF_DATA_DIR.
- Verify the workspace name is valid (no path separators, not empty).
- If a remote backend is wrapped behind Local, fix the remote connection (creds, endpoint) before retrying.
Example fix
null
Defensive patterns
Strategy: try-catch
Validate before calling
// Verify the state path is usable before invoking the local run.
func statePathUsable(dir string) error {
if err := os.MkdirAll(dir, 0o755); err != nil {
return fmt.Errorf("cannot create state dir %s: %w", dir, err)
}
probe := filepath.Join(dir, ".writeprobe")
if err := os.WriteFile(probe, []byte{}, 0o644); err != nil {
return fmt.Errorf("state dir %s not writable: %w", dir, err)
}
_ = os.Remove(probe)
return nil
} Type guard
null
Try / catch
_, stateMgr, diags := b.LocalRun(ctx, op)
if diags.HasErrors() {
if strings.Contains(diags.Err().Error(), "error loading state") {
// surface a hint about state path / permissions
}
return diags
} Prevention
- Ensure TF_DATA_DIR and the state workspace dir are writable by the terraform process.
- Validate workspace names before passing them in (no path separators).
- When wrapping a remote backend behind Local, verify remote connectivity in a preflight check.
When it happens
Trigger: b.StateMgr fails inside createState (cannot create the state file path) or, when the Local backend wraps another backend, the wrapped backend's StateMgr returns errors. HasErrors() is true on the returned sDiags, and the whole diagnostics error is wrapped with %w.
Common situations: The state directory does not exist and cannot be created (permission denied on parent), the workspace name is invalid, or a remote backend wrapped behind Local is unreachable. Also seen when TF_DATA_DIR points to a read-only location.
Related errors
- failed to write state
- backendDiags.Err()
- could not write lock info for
- error deleting workspace
- error loading state
AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11).
Data as JSON: /api/errors/bc4d21ca91c7e47f.
Report an issue: GitHub.
Appendix: source
Thrown at internal/backend/local/backend_local.go:53
// seems bad but we're preserving it for now until we have time to
// properly design this API, vs. just preserving whatever it currently
// happens to do.
op.Type = backendrun.OperationTypeInvalid
op.StateLocker = op.StateLocker.WithContext(ctx)
lr, _, stateMgr, diags := b.localRun(ctx, op)
return lr, stateMgr, diags
}
func (b *Local) localRun(ctx context.Context, op *backendrun.Operation) (*backendrun.LocalRun, *configload.Snapshot, statemgr.Full, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
// Get the latest state.
log.Printf("[TRACE] backend/local: requesting state manager for workspace %q", op.Workspace)
s, sDiags := b.StateMgr(op.Workspace)
if sDiags.HasErrors() {
diags = diags.Append(fmt.Errorf("error loading state: %w", sDiags.Err()))
return nil, nil, nil, diags
}
log.Printf("[TRACE] backend/local: requesting state lock for workspace %q", op.Workspace)
if diags := op.StateLocker.Lock(s, op.Type.String()); diags.HasErrors() {
return nil, nil, nil, diags
}
defer func() {
// If we're returning with errors, and thus not producing a valid
// context, we'll want to avoid leaving the workspace locked.
if diags.HasErrors() {
diags = diags.Append(op.StateLocker.Unlock())
}
}()
log.Printf("[TRACE] backend/local: reading remote state for workspace %q", op.Workspace)
if err := s.RefreshState(); err != nil {
diags = diags.Append(fmt.Errorf("error loading state: %w", err))View on GitHub (pinned to d32a084675)