NationalSecurityAgency/ghidra · error · NoSuchElementException
Private queue no longer exists
Error message
Private queue no longer exists
What it means
Raised as java.util.NoSuchElementException by DomainObjectEventQueues.flushPrivateEventQueue() when the given EventQueueID is not present in the privateEventQueues map. Private queues are created and removed explicitly; once removePrivateEventQueue(id) has run (or the queue was never created), flushing that id is invalid. This is the Java side of Ghidra's domain-object event system, not the Python trace client.
Source
Thrown at Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/framework/data/DomainObjectEventQueues.java:106
DomainObjectChangeSupport docs = new DomainObjectChangeSupport(source, maxDelay, lock);
docs.addListener(listener);
privateEventQueues.put(id, new PrivateQueue(docs));
return id;
}
public boolean removePrivateEventQueue(EventQueueID id) {
PrivateQueue privateQueue = privateEventQueues.remove(id);
if (privateQueue == null) {
return false;
}
privateQueue.cleanable.clean();
return true;
}
public void flushPrivateEventQueue(EventQueueID id) {
PrivateQueue privateQueue = privateEventQueues.get(id);
if (privateQueue == null) {
throw new NoSuchElementException("Private queue no longer exists");
}
privateQueue.flush();
}
public void fireEvent(DomainObjectChangeRecord ev) {
if (eventsEnabled) {
eventQueue.fireEvent(ev);
for (PrivateQueue privateQueue : privateEventQueues.values()) {
privateQueue.fireEvent(ev);
}
}
}
public void setEventsEnabled(boolean eventsEnabled) {
if (this.eventsEnabled == eventsEnabled) {
return;
}
this.eventsEnabled = eventsEnabled;View on GitHub (pinned to d5f144c24d)
Solutions
- Track queue lifecycle so flush always precedes remove for a given id.
- Guard the flush: check removePrivateEventQueue's return value / call getPrivateEventQueue first, or catch NoSuchElementException.
- Ensure dispose paths remove a queue exactly once and do not flush afterwards.
Example fix
// before queues.removePrivateEventQueue(id); queues.flushPrivateEventQueue(id); // throws // after queues.flushPrivateEventQueue(id); queues.removePrivateEventQueue(id);
Defensive patterns
Strategy: validation
Validate before calling
if (!queues.getPrivateEventQueue(id).isPresent()) { /* or track ids */ throw new IllegalStateException("queue gone"); } Try / catch
try {
queues.flushPrivateEventQueue(id);
} catch (NoSuchElementException e) {
// queue already removed; nothing to flush
} Prevention
- Always flush before remove for a given EventQueueID.
- Remove each queue exactly once; guard dispose ordering.
When it happens
Trigger: Calling flushPrivateEventQueue(id) after removePrivateEventQueue(id) for the same id; flushing an id that was never registered; a double-dispose path that removes then flushes.
Common situations: Plugin/component disposal ordering bugs where a queue is removed before a pending flush; race between dispose and an event flush; re-entrant close logic.
Related errors
- Failed to read memory
- Could not get lock
- Must close on the same thread as suppressed the callback
- Unsupported value: {}
- Invalid value for {}
AI-assisted analysis of NationalSecurityAgency/ghidra@d5f144c24d (2026-08-14).
Data as JSON: /api/errors/bb598f7674a3012f.
Report an issue: GitHub.