hashicorp/terraform · warning
(lock ID: " / ")
Error message
%s (lock ID: "%s/%s")
What it means
remoteClient.Lock wraps Workspaces.Lock. When TFC returns ErrWorkspaceLocked (already locked), the backend augments the error with the org/workspace lock-ID string so the user knows what to unlock. The augmented error is wrapped in a statemgr.LockError.
Solutions
- Wait for the in-flight run/operation to finish and release the lock.
- If the lock is stale, run `terraform force-unlock "<org>/<workspace>"` using the ID from the error.
- Serialize concurrent runs on the same workspace via TFC queues or external locking.
Defensive patterns
Strategy: validation
Validate before calling
// Pre-check lock state to give a friendlier error
ws, _ := c.Workspaces.Read(ctx, org, name)
if ws.Locked { return fmt.Errorf("workspace %s/%s already locked; check active runs", org, name) } Prevention
- Serialize runs on a shared workspace.
- Use `terraform force-unlock "<org>/<ws>"` only after confirming the lock is stale.
- Monitor for orphaned locks after CI job kills.
When it happens
Trigger: Workspaces.Lock returns tfe.ErrWorkspaceLocked: another `terraform plan/apply`, a TFC run, or a crashed process holds the workspace lock; a previous run died without unlocking.
Common situations: Concurrent CI jobs on the same workspace; long-running TFC apply still in progress; lock left behind after a killed process (requires force-unlock).
Related errors
- error deleting workspace
- error loading workspace
- lock ID does not match existing lock
- lock ID does not match existing lock ID " /
- (lock ID: " / ")
AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11).
Data as JSON: /api/errors/7704e230127e89bb.
Report an issue: GitHub.
Appendix: source
Thrown at internal/backend/remote/backend_state.go:192
// by implementing remote.ClientForcePusher
func (r *remoteClient) EnableForcePush() {
r.forcePush = true
}
// Lock the remote state.
func (r *remoteClient) Lock(info *statemgr.LockInfo) (string, error) {
ctx := context.Background()
lockErr := &statemgr.LockError{Info: r.lockInfo}
// Lock the workspace.
_, err := r.client.Workspaces.Lock(ctx, r.workspace.ID, tfe.WorkspaceLockOptions{
Reason: tfe.String("Locked by Terraform"),
})
if err != nil {
if err == tfe.ErrWorkspaceLocked {
lockErr.Info = info
err = fmt.Errorf("%s (lock ID: \"%s/%s\")", err, r.organization, r.workspace.Name)
}
lockErr.Err = err
return "", lockErr
}
r.lockInfo = info
return r.lockInfo.ID, nil
}
// Unlock the remote state.
func (r *remoteClient) Unlock(id string) error {
ctx := context.Background()
// We first check if there was an error while uploading the latest
// state. If so, we will not unlock the workspace to prevent any
// changes from being applied until the correct state is uploaded.
if r.stateUploadErr {View on GitHub (pinned to d32a084675)