hashicorp/terraform · error

failed to lock inmem state: %s

Error message

failed to lock inmem state: %s

What it means

When the in-memory backend initializes a brand-new state for a workspace it lazily acquires an init lock via s.Lock(); if that lock call fails (e.g. another holder already locked it), the wrapped error is surfaced here. This protects against two writers creating the initial empty state concurrently.

Source

Thrown at internal/backend/remote-state/inmem/backend.go:147

	states.Lock()
	defer states.Unlock()

	s := states.m[name]
	if s == nil {
		s = &remote.State{
			Client: &RemoteClient{
				Name: name,
			},
		}
		states.m[name] = s

		// to most closely replicate other implementations, we are going to
		// take a lock and create a new state if it doesn't exist.
		lockInfo := statemgr.NewLockInfo()
		lockInfo.Operation = "init"
		lockID, err := s.Lock(lockInfo)
		if err != nil {
			return nil, diags.Append(fmt.Errorf("failed to lock inmem state: %s", err))
		}
		defer s.Unlock(lockID)

		// If we have no state, we have to create an empty state
		if v := s.State(); v == nil {
			if err := s.WriteState(statespkg.NewState()); err != nil {
				return nil, diags.Append(err)
			}
			if err := s.PersistState(nil); err != nil {
				return nil, diags.Append(err)
			}
		}
	}

	return s, diags
}

type stateMap struct {

View on GitHub (pinned to c9def3e214)

Solutions

  1. Call inmem.Reset() between tests to clear stale locks and states.
  2. If using the lock_id config intentionally, ensure the workspace whose state you request is not the one pre-locked, or unlock it first.
  3. Serialize test setup so only one writer initializes a given workspace at a time.

Example fix

// before - each test leaves locks behind, next StateMgr() fails
terraform.Init(ctx)

// after - reset in-memory state (and locks) between tests
inmem.Reset()
terraform.Init(ctx)
Defensive patterns

Strategy: validation

Validate before calling

// Ensure no pre-existing lock for the workspace before requesting a new state mgr
states.Lock(); defer states.Unlock()
if _, locked := locks.m[name]; locked {
    // clear stale test lock or fail fast with a clear message
    delete(locks.m, name)
}
s, diags := b.StateMgr(name)

Prevention

When it happens

Trigger: Calling StateMgr(name) for a workspace that has no state yet (inmem/backend.go:132-159), where stateMgr.Lock returns an error because the global locks map already holds a lock for that name (set, for example, via the lock_id config attribute).

Common situations: A backend configured with `lock_id` in a test that pre-locks the default state, then StateMgr is called and the init lock conflicts with that pre-existing lock; concurrent test setup racing to initialize the same workspace; a stale lock left behind by a crashed test that was never Reset().

Related errors


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