NationalSecurityAgency/ghidra · error · DomainObjectLockedException
Could not get lock
Error message
Could not get lock
What it means
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.
Source
Thrown at Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DomainObjectLockHold.java:49
* // Do stuff while holding the lock
* }
* </pre>
*/
public interface DomainObjectLockHold extends AutoCloseable {
/**
* Wrapper for {@link DomainObject#lock(String)}
*
* @param object the object
* @param reason as in {@link DomainObject#lock(String)}
* @return the hold, which should be used in a {@code try-with-resources} block
* @throws DomainObjectLockedException if the lock could not be obtained
*/
static DomainObjectLockHold lock(DomainObject object, String reason) {
if (object.lock(reason)) {
return new DefaultHold(object);
}
throw new DomainObjectLockedException("Could not get lock");
}
/**
* Wrapper for {@link DomainObject#forceLock(boolean, String)}
*
* @param object the object
* @param rollback as in {@link DomainObject#forceLock(boolean, String)}
* @param reason as in {@link DomainObject#forceLock(boolean, String)}
* @return the hold, which should be used in a {@code try-with-resources} block
*/
static DomainObjectLockHold forceLock(DomainObject object, boolean rollback, String reason) {
object.forceLock(rollback, reason);
return new DefaultHold(object);
}
class DefaultHold implements DomainObjectLockHold {
final DomainObject object;
View on GitHub (pinned to d5f144c24d)
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.
Example fix
// before
try (var hold = DomainObjectLockHold.lock(obj, "edit")) {
mutate(obj);
}
// after
int attempts = 0;
while (true) {
try (var hold = DomainObjectLockHold.lock(obj, "edit")) {
mutate(obj);
break;
} catch (DomainObjectLockedException e) {
if (++attempts > 5) throw e;
Thread.sleep(50);
}
} Defensive patterns
Strategy: retry
Try / catch
int attempt = 0;
while (true) {
try (var hold = DomainObjectLockHold.lock(obj, "edit")) {
mutate(obj);
break;
} catch (DomainObjectLockedException e) {
if (++attempt > MAX_ATTEMPTS) throw e;
Thread.sleep(BACKOFF_MS);
}
} Prevention
- 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.
When it happens
Trigger: 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).
Common situations: 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.
Related errors
- Private queue no longer exists
- Failed to read memory
- Timed out reading or writing target
- Error reading or writing target
- only DBTrace objects are supported
AI-assisted analysis of NationalSecurityAgency/ghidra@d5f144c24d (2026-08-14).
Data as JSON: /api/errors/170c708eab16b793.
Report an issue: GitHub.