NationalSecurityAgency/ghidra · error · KeyError
Inferiors[{inf.num}].Threads[{tnum}] does not exist
Error message
Inferiors[{inf.num}].Threads[{tnum}] does not exist What it means
Raised by find_thread_by_num when iterating gdb.Inferior.threads() finds no thread whose .num equals the requested tnum. The GDB agent treats thread numbers as lookup keys into the inferior; if the thread has exited, been renumbered, or never existed, the loop completes empty. It surfaces as a KeyError because the indexed entity (Inferiors[i].Threads[t]) is absent — a missing-key condition, not a wrong-type condition.
Source
Thrown at Ghidra/Debug/Debugger-agent-gdb/src/main/py/src/ghidragdb/methods.py:154
return find_inf_by_pattern(object, MODULES_PATTERN, "a ModuleContainer")
def find_inf_by_mod_obj(object: TraceObject) -> gdb.Inferior:
return find_inf_by_pattern(object, MODULE_PATTERN, "a Module")
def find_module_name_by_mod_obj(object: TraceObject) -> str:
mat = MODULE_PATTERN.fullmatch(object.path)
if mat is None:
raise TypeError(f"{object} is not a Module")
return mat['modname']
def find_thread_by_num(inf: gdb.Inferior, tnum: int) -> gdb.InferiorThread:
for t in inf.threads():
if t.num == tnum:
return t
raise KeyError(f"Inferiors[{inf.num}].Threads[{tnum}] does not exist")
def find_thread_by_pattern(pattern: re.Pattern, object: TraceObject,
err_msg: str) -> gdb.InferiorThread:
mat = pattern.fullmatch(object.path)
if mat is None:
raise TypeError(f"{object} is not {err_msg}")
infnum = int(mat['infnum'])
tnum = int(mat['tnum'])
inf = find_inf_by_num(infnum)
return find_thread_by_num(inf, tnum)
def find_thread_by_obj(object: TraceObject) -> gdb.InferiorThread:
return find_thread_by_pattern(THREAD_PATTERN, object, "a Thread")
def find_thread_by_stack_obj(object: TraceObject) -> gdb.InferiorThread:View on GitHub (pinned to d5f144c24d)
Solutions
- Re-derive the thread list (inf.threads()) and confirm tnum is present before calling find_thread_by_num.
- In the caller, catch KeyError and treat it as 'thread gone' — refresh the Threads subtree of the trace and return a not-present status instead of propagating.
- Validate the parsed tnum against the current inferior's threads in find_thread_by_pattern before delegating.
- Ensure trace invalidation hooks fire on thread-exit events so stale [tnum] objects are removed before method dispatch.
Example fix
// before
t = find_thread_by_num(inf, tnum)
// after
nums = {t.num for t in inf.threads()}
if tnum not in nums:
# thread exited; refresh trace Threads subtree
return None
t = find_thread_by_num(inf, tnum) Defensive patterns
Strategy: validation
Validate before calling
tnums = {t.num for t in inf.threads()}
if tnum not in tnums:
# thread gone; refresh trace Threads subtree
return None
t = find_thread_by_num(inf, tnum) Type guard
def thread_exists(inf: gdb.Inferior, tnum: int) -> bool:
return any(t.num == tnum for t in inf.threads()) Try / catch
try:
t = find_thread_by_num(inf, tnum)
except KeyError:
# thread exited between event and dispatch; invalidate trace node
invalidate_thread_obj(inf.num, tnum)
return None Prevention
- re-query inf.threads() before lookup in long sessions
- wire thread-exit hooks to remove stale Threads[t] trace objects
- treat thread lookups as inherently racy and handle absence
When it happens
Trigger: Calling find_thread_by_num(inf, tnum) after the thread exited (e.g. on stop/cont events where GDB pruned the thread), with a tnum parsed from a stale TraceObject path, or with a tnum that exceeds the current thread range. Reached indirectly via find_thread_by_obj/find_thread_by_pattern which extract tnum from the object path and delegate here.
Common situations: Stale trace objects referencing threads that have since exited (common in long debug sessions, fork/exec, or GDB's scheduler-locking scenarios); race between a 'thread exited' event and a method handler that still holds the old path; mismatched inferior after a re-run where thread numbering restarted.
Related errors
- Inferiors[{thread.inferior.num}].Threads[{thread.num}].Stack
- No such register: {name}
- Breakpoints[{breaknum}] does not exist
- {object} is not a Module
- Unsupported value: {}
AI-assisted analysis of NationalSecurityAgency/ghidra@d5f144c24d (2026-08-14).
Data as JSON: /api/errors/837e0ecfa5793b2c.
Report an issue: GitHub.