{"record":{"id":"8b5ff4d212e83f5d","repo":"NationalSecurityAgency/ghidra","slug":"processes-proc-getprocessid-threads-tnum-d","errorCode":null,"errorMessage":"Processes[{proc.GetProcessID()}].Threads[{tnum}] does not exist","messagePattern":"Processes\\[(.+?)\\]\\.Threads\\[(.+?)\\] does not exist","errorType":"exception","errorClass":"KeyError","httpStatus":null,"severity":"error","filePath":"Ghidra/Debug/Debugger-agent-lldb/src/main/py/src/ghidralldb/methods.py","lineNumber":117,"sourceCode":"\n\ndef find_proc_by_mem_obj(object: TraceObject) -> lldb.SBProcess:\n    return find_proc_by_pattern(object, MEMORY_PATTERN, \"a Memory\")\n\n\ndef find_proc_by_modules_obj(object: TraceObject) -> lldb.SBProcess:\n    return find_proc_by_pattern(object, MODULES_PATTERN, \"a ModuleContainer\")\n\n\ndef find_proc_by_frame(object: TraceObject) -> lldb.SBProcess:\n    return find_proc_by_pattern(object, FRAME_PATTERN, \"a StaclFrame\")\n\n\ndef find_thread_by_num(proc: lldb.SBThread, tnum: int) -> lldb.SBThread:\n    for t in proc.threads:\n        if t.GetThreadID() == tnum:\n            return t\n    raise KeyError(\n        f\"Processes[{proc.GetProcessID()}].Threads[{tnum}] does not exist\")\n\n\ndef find_thread_by_pattern(pattern: re.Pattern, object: TraceObject,\n                           err_msg: str) -> lldb.SBThread:\n    mat = pattern.fullmatch(object.path)\n    if mat is None:\n        raise TypeError(f\"{object} is not {err_msg}\")\n    procnum = int(mat['procnum'])\n    tnum = int(mat['tnum'])\n    proc = find_proc_by_num(procnum)\n    return find_thread_by_num(proc, tnum)\n\n\ndef find_thread_by_obj(object: TraceObject) -> lldb.SBThread:\n    return find_thread_by_pattern(THREAD_PATTERN, object, \"a Thread\")\n\n","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/NationalSecurityAgency/ghidra/blob/d5f144c24d6bc53c9cbf4448c6d11143e7696206/Ghidra/Debug/Debugger-agent-lldb/src/main/py/src/ghidralldb/methods.py#L99-L135","documentation":"Raised by find_thread_by_num when iterating proc.threads finds no thread whose GetThreadID() matches the requested tnum. The Ghidra LLDB agent resolves trace object paths of the form Processes[<procnum>].Threads[<tnum>] to live LLDB SBThread objects; this error fires when the thread ID extracted from the path does not exist in the current process thread list.","triggerScenarios":"A Ghidra trace method (e.g. activate, read_reg, step) calls find_thread_by_pattern, which extracts tnum from the Threads[<tnum>] segment of the TraceObject path and passes it to find_thread_by_num. The LLDB SBProcess.threads collection contains no SBThread whose GetThreadID() equals that integer.","commonSituations":"The target thread has exited or been terminated between trace snapshot and operation. A multi-threaded target where threads are dynamically created and destroyed left stale IDs in the trace. The process state changed (e.g. after a continue or kill) without refreshing the trace.","solutions":["Re-snapshot the trace so object paths reflect the live thread set (e.g. re-run 'ghidra trace tx-start' followed by the appropriate put-* commands).","Verify the thread still exists by checking proc.threads for the matching GetThreadID() before invoking the trace method.","Catch KeyError in the method handler and return a trace-rpc error so Ghidra's UI can re-sync its object tree."],"exampleFix":"# before: stale tnum passed blindly\nproc = find_proc_by_num(procnum)\nthread = find_thread_by_num(proc, tnum)\n\n# after: verify existence first\ntids = [t.GetThreadID() for t in proc.threads]\nif tnum not in tids:\n    raise KeyError(f\"Processes[{proc.GetProcessID()}].Threads[{tnum}] does not exist\")\nthread = next(t for t in proc.threads if t.GetThreadID() == tnum)","handlingStrategy":"try-catch","validationCode":"proc = find_proc_by_num(procnum)\ntids = {t.GetThreadID() for t in proc.threads}\nif tnum not in tids:\n    # do not call find_thread_by_num; refresh trace or report error\n    pass","typeGuard":null,"tryCatchPattern":"try:\n    thread = find_thread_by_num(proc, tnum)\nexcept KeyError:\n    # thread no longer exists; refresh trace and retry or report\n    refresh_trace_threads(proc)\n    thread = find_thread_by_num(proc, tnum)","preventionTips":["Refresh the trace before operating on thread paths after the target continues or changes state.","Cache thread IDs at snapshot time and compare against proc.threads before use.","Catch KeyError in RPC method handlers and return a structured error so Ghidra can re-sync."],"tags":["lldb","debugger-agent","thread-not-found","keyerror","trace-object"],"backgroundTag":null,"analyzedSha":"d5f144c24d6bc53c9cbf4448c6d11143e7696206","analyzedAt":"2026-08-14T01:00:57.564Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}