{"record":{"id":"aac5fc00f1fcf6dd","repo":"hashicorp/terraform","slug":"cannot-lock-workspace-already-locked-for-workspac","errorCode":null,"errorMessage":"Cannot lock workspace; already locked for workspace creation: %s","messagePattern":"Cannot lock workspace; already locked for workspace creation: (.+?)","errorType":"exception","errorClass":"statemgr.LockError","httpStatus":null,"severity":"error","filePath":"internal/backend/remote-state/pg/client.go","lineNumber":124,"sourceCode":"\t\tvar innerDidLock []byte\n\t\terr := innerRow.Scan(&innerDidLock)\n\t\tif err != nil {\n\t\t\treturn \"\", &statemgr.LockError{Info: info, Err: err}\n\t\t}\n\t\tif string(innerDidLock) == \"false\" {\n\t\t\treturn \"\", &statemgr.LockError{Info: info, Err: fmt.Errorf(\"Already locked for workspace creation: %s\", c.Name)}\n\t\t}\n\t\tinfo.Path = \"-1\"\n\tcase err != nil:\n\t\treturn \"\", &statemgr.LockError{Info: info, Err: err}\n\tcase string(didLock) == \"false\":\n\t\t// Existing workspace is already locked. Release the attempted creation lock.\n\t\tlockUnlock(\"-1\")\n\t\treturn \"\", &statemgr.LockError{Info: info, Err: fmt.Errorf(\"Workspace is already locked: %s\", c.Name)}\n\tcase string(didLockForCreate) == \"false\":\n\t\t// Someone has the creation lock already. Release the existing workspace because it might not be safe to touch.\n\t\tlockUnlock(string(pgLockId))\n\t\treturn \"\", &statemgr.LockError{Info: info, Err: fmt.Errorf(\"Cannot lock workspace; already locked for workspace creation: %s\", c.Name)}\n\tdefault:\n\t\t// Existing workspace is now locked. Release the attempted creation lock.\n\t\tlockUnlock(\"-1\")\n\t\tinfo.Path = string(pgLockId)\n\t}\n\tc.info = info\n\n\treturn info.ID, nil\n}\n\nfunc (c *RemoteClient) getLockInfo() (*statemgr.LockInfo, error) {\n\treturn c.info, nil\n}\n\nfunc (c *RemoteClient) Unlock(id string) error {\n\tif c.info != nil && c.info.Path != \"\" {\n\t\tquery := `SELECT pg_advisory_unlock(%s)`\n\t\trow := c.Client.QueryRow(fmt.Sprintf(query, c.info.Path))","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/hashicorp/terraform/blob/c9def3e214014c1188faabfc4a5bde5095139765/internal/backend/remote-state/pg/client.go#L106-L142","documentation":"Returned by RemoteClient.Lock (pg/client.go:124). The workspace row exists and the per-workspace lock was acquired, but the global creation lock pg_try_advisory_lock(-1) returned false — another session is mid-creation of some workspace. Per the code, Terraform releases the just-acquired workspace lock and fails, because mutating a workspace while another creation is in flight is considered unsafe.","triggerScenarios":"Concurrent first-time creation of a different workspace while you try to operate on an existing one; a stuck session holding the -1 advisory lock.","commonSituations":"Shared Postgres backend used by multiple teams where one team's workspace creation overlaps another team's apply; stale -1 lock from a crashed create.","solutions":["Retry once the in-flight workspace creation completes — the -1 lock is transient.","Check pg_locks for advisory lock -1 and terminate the holder if stale.","Avoid overlapping workspace creation with active applies on the same backend."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Check the creation lock is free before operating on an existing workspace\n// SELECT 1 FROM pg_locks WHERE locktype='advisory' AND objid=-1;","typeGuard":"// Returns *statemgr.LockError, carrying Info about the creation-lock holder\n// var lockErr *statemgr.LockError\n// if errors.As(err, &lockErr) { /* inspect lockErr.Info */ }","tryCatchPattern":"// Retryable: the creation lock is transient\n// for i := 0; i < 5; i++ {\n//   _, err := client.Lock(info)\n//   var le *statemgr.LockError\n//   if errors.As(err, &le) && strings.Contains(le.Error(), \"workspace creation\") {\n//     time.Sleep(time.Duration(1<<i) * time.Second); continue\n//   }\n//   return err\n// }","preventionTips":["Avoid scheduling workspace creation concurrently with applies on the same backend.","Clear stale -1 advisory locks via pg_terminate_backend.","Document that creation locks are global across all workspaces."],"tags":["postgres","locking","concurrency","workspace"],"analyzedSha":"c9def3e214014c1188faabfc4a5bde5095139765","analyzedAt":"2026-08-07T15:39:49.278Z","schemaVersion":2},"datasetVersion":"2026-08-07T21:17:07.882Z"}