NationalSecurityAgency/ghidra · error · RuntimeException
Timed out waiting for thread to stop
Error message
Timed out waiting for thread to stop
What it means
Thrown by ghidraTraceWaitStopped(int timeout) when the target thread does not report isSuspended()==true within the given timeout milliseconds. The method polls every 100ms, and if elapsed time exceeds the timeout it aborts — the trace cannot proceed because operations require a stopped target.
Source
Thrown at Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/rmi/jpda/JdiCommands.java:2177
}
public void ghidraTraceSyncSynthStopped() {
connector.getHooks().onStop(null, state.trace);
}
public void ghidraTraceWaitStopped(int timeout) {
ThreadReference currentThread = connector.getJdi().getCurrentThread();
if (currentThread == null) {
return;
}
long start = System.currentTimeMillis();
while (!currentThread.isSuspended()) {
currentThread = connector.getJdi().getCurrentThread();
try {
Thread.sleep(100);
long elapsed = System.currentTimeMillis() - start;
if (elapsed > timeout) {
throw new RuntimeException("Timed out waiting for thread to stop");
}
}
catch (InterruptedException e) {
Msg.error(this, "Wait interrupted");
}
}
}
public void execute(ClassType ct, ThreadReference thread, Method method, List<Value> args,
int options) {
try {
Value val = ct.invokeMethod(thread, method, args, options);
System.err.println(val);
}
catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
}View on GitHub (pinned to d5f144c24d)
Solutions
- Increase the timeout value passed to ghidraTraceWaitStopped to accommodate a slow target.
- Confirm the suspend request or breakpoint actually reached the target VM (check JDI event requests).
- If the thread is genuinely stuck, interrupt or forcibly suspend it via the connector before waiting.
- Re-issue the wait after a short delay in case of transient event-delivery latency.
Example fix
// before ghidraTraceWaitStopped(1000); // too short, throws // after ghidraTraceWaitStopped(10000); // allow more time for the suspend to land
Defensive patterns
Strategy: retry
Validate before calling
// Verify suspend before waiting
ThreadReference t = connector.getJdi().getCurrentThread();
if (t != null && t.isSuspended()) { /* already stopped, no wait needed */ }
else { /* choose a generous timeout */ } Try / catch
try { ghidraTraceWaitStopped(timeoutMs); }
catch (RuntimeException e) {
if (e.getMessage().contains("Timed out")) { /* optionally re-issue once with a larger timeout */ }
else throw e;
} Prevention
- Size the timeout to the slowest expected target operation, not the average.
- Confirm the suspend/breakpoint request reached the target VM before waiting.
- Watch the target's terminal for signs it is still executing.
When it happens
Trigger: Calling ghidraTraceWaitStopped after requesting a suspend (or expecting a breakpoint hit) but the thread keeps running. Causes: the suspend request is still in flight, the target is executing a long native call, the breakpoint was never hit, or the JDI event stream is delayed.
Common situations: Timeout value too small for a slow or heavily loaded target; the breakpoint condition was never satisfied; the target is stuck in a native/JIT-compiled region that doesn't honor suspend promptly; event delivery latency over a remote JDI connection.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Transaction already started
- Address must be in the form 'host:port'
- Port must be numeric
- Error connecting to ${address}: ${e}
- Attempt to create existing memory
AI-assisted analysis of NationalSecurityAgency/ghidra@d5f144c24d (2026-08-14).
Data as JSON: /api/errors/6d29ce16e44517d5.
Report an issue: GitHub.