NationalSecurityAgency/ghidra · error · KeyError

Invalid domain object id: {request.oid.id}

Error message

Invalid domain object id: {request.oid.id}

What it means

Raised as KeyError by Client._handle_invoke_method() when an incoming invoke-method request references an oid (domain/trace object id) that is not present in the server's self._traces map. The trace was never created, was already closed/removed, or the id is stale.

Source

Thrown at Ghidra/Debug/Debugger-rmi-trace/src/main/py/src/ghidratrace/client.py:1352

        def _handle(reply: bufs.ReplyDisassemble) -> int:
            return reply.length
        return self._batch_or_now(root, 'reply_disassemble', _handle)

    def _negotiate(self, description: str) -> str:
        root = bufs.RootMessage()
        root.request_negotiate.version = VERSION
        root.request_negotiate.description = description
        self._write_methods(root.request_negotiate.methods,
                            self._method_registry._methods.values())

        def _handle(reply: bufs.ReplyNegotiate) -> str:
            return reply.description
        return self._now(root, 'reply_negotiate', _handle)

    def _handle_invoke_method(self, request: bufs.XRequestInvokeMethod) -> Any:
        if request.HasField('oid'):
            if request.oid.id not in self._traces:
                raise KeyError(f"Invalid domain object id: {request.oid.id}")
            trace = self._traces[request.oid.id]
        else:
            trace = None
        name = request.name
        if not name in self._method_registry._methods:
            raise KeyError(f"Invalid method name: {name}")
        method = self._method_registry._methods[name]
        kwargs = self._read_arguments(request.arguments, trace)
        return method.callback(**kwargs)


class Receiver(Thread):
    __slots__ = ('client', 'req_queue', '_is_shutdown')

    def __init__(self, client: Client) -> None:
        super().__init__(daemon=True)
        self.client: Client = client
        self.req_queue: deque[RemoteResult[Any, Any]] = deque()

View on GitHub (pinned to d5f144c24d)

Solutions

  1. Re-open/refresh the Trace handle on the client before invoking trace-scoped methods after any disconnect or close.
  2. Discard cached oids when the corresponding Trace is closed.
  3. Catch KeyError around invoke and re-establish the trace, then retry once.

Example fix

# before
trace.some_method()  # oid no longer valid on server
# after
try:
    trace.some_method()
except KeyError:
    trace = client.open_trace(...)
    trace.some_method()
Defensive patterns

Strategy: try-catch

Validate before calling

if oid not in client._traces:
    raise KeyError(f'oid {oid} not open on server')

Try / catch

try:
    result = method(...)
except KeyError:
    trace = reopen_trace()
    result = method(...)

Prevention

When it happens

Trigger: A client invokes a trace-scoped method after the trace was closed on the server; the client reused a cached oid from a previous connection; the request references an id that was never opened in this session.

Common situations: Long-lived client holding stale trace handles across a server restart; race between close and a queued method call; client/server desync after an error.

Related errors


AI-assisted analysis of NationalSecurityAgency/ghidra@d5f144c24d (2026-08-14). Data as JSON: /api/errors/3d5de3defc18673e. Report an issue: GitHub.