{"record":{"id":"170c708eab16b793","repo":"NationalSecurityAgency/ghidra","slug":"could-not-get-lock","errorCode":null,"errorMessage":"Could not get lock","messagePattern":"Could not get lock","errorType":"exception","errorClass":"DomainObjectLockedException","httpStatus":null,"severity":"error","filePath":"Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DomainObjectLockHold.java","lineNumber":49,"sourceCode":" * \t// Do stuff while holding the lock\n * }\n * </pre>\n */\npublic interface DomainObjectLockHold extends AutoCloseable {\n\n\t/**\n\t * Wrapper for {@link DomainObject#lock(String)}\n\t * \n\t * @param object the object\n\t * @param reason as in {@link DomainObject#lock(String)}\n\t * @return the hold, which should be used in a {@code try-with-resources} block\n\t * @throws DomainObjectLockedException if the lock could not be obtained\n\t */\n\tstatic DomainObjectLockHold lock(DomainObject object, String reason) {\n\t\tif (object.lock(reason)) {\n\t\t\treturn new DefaultHold(object);\n\t\t}\n\t\tthrow new DomainObjectLockedException(\"Could not get lock\");\n\t}\n\n\t/**\n\t * Wrapper for {@link DomainObject#forceLock(boolean, String)}\n\t * \n\t * @param object the object\n\t * @param rollback as in {@link DomainObject#forceLock(boolean, String)}\n\t * @param reason as in {@link DomainObject#forceLock(boolean, String)}\n\t * @return the hold, which should be used in a {@code try-with-resources} block\n\t */\n\tstatic DomainObjectLockHold forceLock(DomainObject object, boolean rollback, String reason) {\n\t\tobject.forceLock(rollback, reason);\n\t\treturn new DefaultHold(object);\n\t}\n\n\tclass DefaultHold implements DomainObjectLockHold {\n\t\tfinal DomainObject object;\n","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/NationalSecurityAgency/ghidra/blob/d5f144c24d6bc53c9cbf4448c6d11143e7696206/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DomainObjectLockHold.java#L31-L67","documentation":"DomainObjectLockHold.lock wraps DomainObject.lock(reason). When lock returns false the domain object is already held by another transaction/thread, so DomainObjectLockedException is thrown. This is an expected concurrency-conflict failure (not a bug): only one writer may hold the modification lock at a time.","triggerScenarios":"object.lock(reason) returns false - another holder currently owns the modification lock (another thread editing the program, a long-running transaction, the GUI mid-edit, or a re-entrant attempt that the implementation disallows).","commonSituations":"Concurrent edits to one DomainObject; a background task locking while the GUI holds the lock; tight test loops that race on the same object; a leaked/unclosed lock hold keeping the object locked.","solutions":["Use try-with-resources around DomainObjectLockHold.lock and handle DomainObjectLockedException (retry with backoff or abort gracefully).","Shorten the critical section - acquire the lock as late as possible and close it promptly.","Make sure every prior hold is closed (no leaked AutoCloseable) so the object isn't permanently locked.","As a last resort for administrative recovery, DomainObjectLockHold.forceLock overrides the lock - but this disrupts any other active transaction."],"exampleFix":"// before\ntry (var hold = DomainObjectLockHold.lock(obj, \"edit\")) {\n    mutate(obj);\n}\n// after\nint attempts = 0;\nwhile (true) {\n    try (var hold = DomainObjectLockHold.lock(obj, \"edit\")) {\n        mutate(obj);\n        break;\n    } catch (DomainObjectLockedException e) {\n        if (++attempts > 5) throw e;\n        Thread.sleep(50);\n    }\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"int attempt = 0;\nwhile (true) {\n    try (var hold = DomainObjectLockHold.lock(obj, \"edit\")) {\n        mutate(obj);\n        break;\n    } catch (DomainObjectLockedException e) {\n        if (++attempt > MAX_ATTEMPTS) throw e;\n        Thread.sleep(BACKOFF_MS);\n    }\n}","preventionTips":["Keep lock hold sections short and always use try-with-resources to avoid leaking locks.","Retry with backoff on DomainObjectLockedException rather than failing immediately.","Avoid concurrent writers on the same DomainObject where possible."],"tags":["concurrency","locking","domain-object"],"backgroundTag":null,"analyzedSha":"d5f144c24d6bc53c9cbf4448c6d11143e7696206","analyzedAt":"2026-08-14T01:00:57.564Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}