hashicorp/terraform · error

Error unlocking oci state. Lock ID: %s Error: %s You may h

Error message

Error unlocking oci state. Lock ID: %s

Error: %s

You may have to force-unlock this state in order to use it again.

What it means

Emitted by the inline lockUnlock closure (backend_state.go:78-83) using the errStateUnlock constant when stateMgr.Unlock fails inside the init-write flow. The lock was acquired but could not be released, so the workspace is left locked. The message deliberately includes the lock ID and tells the user to force-unlock.

Source

Thrown at internal/backend/remote-state/oci/backend_state.go:80

			exists = true
			break
		}
	}

	// We need to create the object so it's listed by States.
	if !exists {
		// take a lock on this state while we write it
		lockInfo := statemgr.NewLockInfo()
		lockInfo.Operation = "init"
		lockId, err := b.client.Lock(lockInfo)
		if err != nil {
			return nil, diags.Append(fmt.Errorf("failed to lock oci state: %s", err))
		}

		// Local helper function so we can call it multiple places
		lockUnlock := func(parent error) error {
			if err := stateMgr.Unlock(lockId); err != nil {
				return fmt.Errorf(strings.TrimSpace(errStateUnlock), lockId, err)
			}
			return parent
		}

		// Grab the value
		// This is to ensure that no one beat us to writing a state between
		// the `exists` check and taking the lock.
		if err := stateMgr.RefreshState(); err != nil {
			err = lockUnlock(err)
			return nil, diags.Append(err)
		}

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

View on GitHub (pinned to d32a084675)

Solutions

  1. Copy the Lock ID from the message and run `terraform force-unlock <LOCK_ID>` after verifying no operation is active.
  2. Inspect the bucket for the lock object; if it is already gone, the unlock effectively succeeded and you can proceed.
  3. Stabilize IAM/network before retrying; an unlock that fails once will keep failing for the same reason until the underlying cause is fixed.
  4. If force-unlock itself fails, delete the lock object directly in Object Storage.

Example fix

# recovery from the printed message:
# Error unlocking oci state. Lock ID: 2024-...
# You may have to force-unlock this state in order to use it again.
terraform force-unlock 2024-...
Defensive patterns

Strategy: fallback

Type guard

func isUnlockFailure(err error) bool {
    return err != nil && strings.Contains(err.Error(), "Error unlocking oci state")
}

Try / catch

// After the init-write flow, if unlock fails, surface the lock ID for force-unlock
if err := lockUnlock(nil); err != nil {
    // The state is now locked; instruct the user to force-unlock
    log.Printf("[WARN] state left locked: %v. Run `terraform force-unlock <ID>`", err)
    return err
}

Prevention

When it happens

Trigger: stateMgr.Unlock internally calls RemoteClient.Unlock; that fails if the lock file was concurrently deleted (etag mismatch / 404), if the lock ID no longer matches (314), if credentials/permissions changed mid-operation, or on a transient network error during the delete.

Common situations: A second user force-unlocked the lock between your Lock and Unlock; IAM permission was revoked mid-run; a network blip hit exactly the unlock call; manual deletion of the lock object during init.

Related errors


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