NationalSecurityAgency/ghidra · error · RuntimeError
Timed out waiting for thread to stop
Error message
Timed out waiting for thread to stop
What it means
Raised by ghidra_util_wait_stopped when the target does not reach a stopped state within the given timeout (default 1s). The loop polls util.get_process().state every 0.1s and raises at commands.py:2092 once elapsed time exceeds the timeout. IMPORTANT BUG: the loop compares against `lldb.eStateRunnig` (typo, missing 'n'); the correct constant is `lldb.eStateRunning`. Accessing the misspelled attribute typically raises AttributeError before the timeout branch, so this exact message is effectively a dead path until the typo is fixed.
Source
Thrown at Ghidra/Debug/Debugger-agent-lldb/src/main/py/src/ghidralldb/commands.py:2092
An optional timeout may be given in seconds. If omitted, the timeout is 1
second.
"""
args = shlex.split(command)
if len(args) == 0:
timeout = 1
elif len(args) == 1:
timeout = int(args[0])
else:
raise RuntimeError("Usage: ghidra util wait-stopped [SECONDS]")
start = time.time()
p = util.get_process()
while p is not None and p.state == lldb.eStateRunnig:
time.sleep(0.1)
p = util.get_process() # I suppose it could change
if time.time() - start > timeout:
raise RuntimeError('Timed out waiting for thread to stop')
print(f"Finished wait. State={p.state}")
View on GitHub (pinned to d5f144c24d)
Solutions
- Increase the timeout: `ghidra util wait-stopped 10`.
- Ensure the target was actually commanded to stop (breakpoint/step) before waiting; wait-stopped cannot create a stop.
- Fix the typo at commands.py:2088: `lldb.eStateRunning` so the poll correctly detects running state and the timeout path works as designed.
- If you see AttributeError mentioning eStateRunnig, that is the same line — patch the constant name.
Example fix
// before while p is not None and p.state == lldb.eStateRunnig: // after while p is not None and p.state == lldb.eStateRunning:
Defensive patterns
Strategy: try-catch
Validate before calling
import lldb, time
# Guard before waiting: only wait if a stop is actually expected,
# and use the CORRECT constant (eStateRunning, not the codebase typo).
running = getattr(lldb, 'eStateRunning', None)
if running is None:
raise AttributeError("lldb.eStateRunning missing; cannot poll state") Try / catch
try:
dbg.HandleCommand('ghidra util wait-stopped 10')
except RuntimeError as e:
if 'Timed out waiting' in str(e):
# target did not stop in time — retry with larger timeout or
# verify a stop was actually requested
... Prevention
- Give an explicit larger timeout for slow/remote targets.
- Only wait after issuing a command that will stop the target.
- Patch the eStateRunnig typo (commands.py:2088) so the poll works; otherwise you'll see AttributeError instead of this timeout.
When it happens
Trigger: Issuing `ghidra util wait-stopped` (or with N seconds) when the target is still running/resuming and doesn't stop within the window — e.g. right after `process continue` on a long-running target, or with a too-small timeout on a slow remote/gdb-protocol target. In practice you may instead hit AttributeError on `lldb.eStateRunnig`.
Common situations: Race after a continue/step where the stop event hasn't arrived; slow remote debugging where 1s default is too short; or a target that never stops (runs to exit). The typo means the intended 'running' comparison is broken.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Usage: ghidra util wait-stopped [SECONDS]
- Usage: ghidra trace disassemble ADDRESS
- Usage: ghidra trace put-processes
- Usage: ghidra trace put-available
- Usage: ghidra trace put-breakpoints
AI-assisted analysis of NationalSecurityAgency/ghidra@d5f144c24d (2026-08-14).
Data as JSON: /api/errors/530ebf46ae717c97.
Report an issue: GitHub.