NationalSecurityAgency/ghidra · error · KeyError
Watchpoints[{watchnum}] does not exist
Error message
Watchpoints[{watchnum}] does not exist What it means
Raised by find_wpt_by_number when iterating the target's watchpoint list (util.get_target().GetWatchpointAtIndex) finds no SBWatchpoint whose GetID() equals the requested watchnum. Like breakpoints, LLDB has no direct watchpoint-by-ID lookup, so the agent scans the list linearly.
Source
Thrown at Ghidra/Debug/Debugger-agent-lldb/src/main/py/src/ghidralldb/methods.py:197
if mat is None:
raise TypeError(f"{object} is not {err_msg}")
breaknum = int(mat['breaknum'])
return find_bpt_by_number(breaknum)
def find_bpt_by_obj(object: TraceObject) -> lldb.SBBreakpoint:
return find_bpt_by_pattern(PROC_BREAK_PATTERN, object, "a BreakpointSpec")
# Oof. no lldb/Python method to get breakpoint by number
# I could keep my own cache in a dict, but why?
def find_wpt_by_number(watchnum: int) -> lldb.SBWatchpoint:
# TODO: If len exceeds some threshold, use binary search?
for i in range(0, util.get_target().GetNumWatchpoints()):
w = util.get_target().GetWatchpointAtIndex(i)
if w.GetID() == watchnum:
return w
raise KeyError(f"Watchpoints[{watchnum}] does not exist")
def find_wpt_by_pattern(pattern: re.Pattern, object: TraceObject,
err_msg: str) -> lldb.SBWatchpoint:
mat = pattern.fullmatch(object.path)
if mat is None:
raise TypeError(f"{object} is not {err_msg}")
watchnum = int(mat['watchnum'])
return find_wpt_by_number(watchnum)
def find_wpt_by_obj(object: TraceObject) -> lldb.SBWatchpoint:
return find_wpt_by_pattern(PROC_WATCH_PATTERN, object, "a WatchpointSpec")
def find_bptlocnum_by_pattern(pattern: re.Pattern, object: TraceObject,
err_msg: str) -> Tuple[int, int]:
mat = pattern.fullmatch(object.path)View on GitHub (pinned to d5f144c24d)
Solutions
- Refresh the trace watchpoint list with 'ghidra trace put-watches' before operating on watchpoint paths.
- Check [util.get_target().GetWatchpointAtIndex(i).GetID() for i in range(util.get_target().GetNumWatchpoints())] for the ID.
- Catch KeyError and trigger a trace re-sync.
Example fix
# before
wpt = find_wpt_by_number(watchnum)
# after: validate
wids = {
util.get_target().GetWatchpointAtIndex(i).GetID()
for i in range(util.get_target().GetNumWatchpoints())
}
if watchnum not in wids:
raise KeyError(f"Watchpoints[{watchnum}] does not exist")
wpt = find_wpt_by_number(watchnum) Defensive patterns
Strategy: try-catch
Validate before calling
tgt = util.get_target()
existing = {tgt.GetWatchpointAtIndex(i).GetID() for i in range(tgt.GetNumWatchpoints())}
if watchnum not in existing:
pass # do not call find_wpt_by_number Try / catch
try:
wpt = find_wpt_by_number(watchnum)
except KeyError:
refresh_watchpoints()
wpt = find_wpt_by_number(watchnum) Prevention
- Refresh the trace watchpoint list after watchpoint changes.
- Verify watchpoint IDs exist in the target before operating on watchpoint paths.
- Catch KeyError and trigger a trace re-sync.
When it happens
Trigger: find_wpt_by_pattern extracts watchnum from the Watchpoints[<watchnum>] path segment and calls find_wpt_by_number. The for-loop over GetNumWatchpoints() does not find a matching watchpoint.
Common situations: The watchpoint was deleted or hit-and-removed between trace snapshot and operation. The watchnum is stale or from a prior target session.
Related errors
- Processes[{proc.GetProcessID()}].Threads[{tnum}] does not ex
- Breakpoints[{breaknum}] does not exist
- Usage: ghidra trace disassemble ADDRESS
- Usage: ghidra trace put-processes
- Usage: ghidra trace put-available
AI-assisted analysis of NationalSecurityAgency/ghidra@d5f144c24d (2026-08-14).
Data as JSON: /api/errors/09866eace74d3bea.
Report an issue: GitHub.