{"record":{"id":"84e69babf137d04c","repo":"NationalSecurityAgency/ghidra","slug":"object-is-not-err-msg","errorCode":null,"errorMessage":"{object} is not {err_msg}","messagePattern":"(.+?) is not (.+?)","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"Ghidra/Debug/Debugger-agent-dbgeng/src/main/py/src/ghidradbg/exdi/exdi_methods.py","lineNumber":34,"sourceCode":"import re\n\nfrom ghidratrace import sch\nfrom ghidratrace.client import (MethodRegistry, ParamDesc, Address,\n                                AddressRange, TraceObject)\nfrom ghidradbg import util, commands, methods\nfrom ghidradbg.methods import REGISTRY, SESSIONS_PATTERN, SESSION_PATTERN, extre\n\nfrom . import exdi_commands\n\nXPROCESSES_PATTERN = extre(SESSION_PATTERN, '\\\\.ExdiProcesses')\nXPROCESS_PATTERN = extre(XPROCESSES_PATTERN, '\\\\[(?P<procnum>\\\\d*)\\\\]')\nXTHREADS_PATTERN = extre(XPROCESS_PATTERN, '\\\\.Threads')\n\n\ndef find_pid_by_pattern(pattern, object, err_msg):\n    mat = pattern.fullmatch(object.path)\n    if mat is None:\n        raise TypeError(f\"{object} is not {err_msg}\")\n    pid = int(mat['procnum'])\n    return pid\n\n\ndef find_pid_by_obj(object):\n    return find_pid_by_pattern(XTHREADS_PATTERN, object, \"an ExdiThreadsContainer\")\n\n\nclass ExdiProcessContainer(TraceObject):\n    pass\n\n\nclass ExdiThreadContainer(TraceObject):\n    pass\n\n\n@REGISTRY.method(action='refresh', display=\"Refresh Target Processes\")\ndef refresh_exdi_processes(node: ExdiProcessContainer) -> None:","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/NationalSecurityAgency/ghidra/blob/d5f144c24d6bc53c9cbf4448c6d11143e7696206/Ghidra/Debug/Debugger-agent-dbgeng/src/main/py/src/ghidradbg/exdi/exdi_methods.py#L16-L52","documentation":"Raised by find_pid_by_pattern() in exdi_methods.py:34 when a TraceObject's path does not match the expected Exdi session/process pattern. This is a type/shape guard: it ensures the object passed to an Exdi-scoped method actually represents an Exdi threads/processes container before extracting the procnum capture group. The error message is filled by the caller's err_msg (e.g. 'an ExdiThreadsContainer').","triggerScenarios":"Passing a non-Exdi TraceObject (e.g. a normal Process or Thread object) to an Exdi-specific method that calls find_pid_by_obj/find_pid_by_pattern; path shape changed due to a schema mismatch; using Exdi methods when Exdi is not the active transport.","commonSituations":"Mixing the regular dbgeng method routing with the Exdi method routing; schema version drift where path prefixes differ; calling Exdi helpers from a non-Exdi (native dbgeng) session.","solutions":["Ensure Exdi is the active debug transport (util.is_exdi() true) before invoking Exdi-scoped methods.","Pass an object whose path matches the ExdiProcesses/ExdiThreads schema (e.g. 'Sessions[1].ExdiProcesses[0].Threads').","Switch to the non-Exdi equivalent method if you are in a native dbgeng session."],"exampleFix":"// before\n# in a native dbgeng session, calling an Exdi helper:\nfind_pid_by_obj(process_obj)   # TypeError: ... is not an ExdiThreadsContainer\n\n// after\n# use the native helper instead:\nfind_proc_by_obj(process_obj)","handlingStrategy":"type-guard","validationCode":"import re\nfrom ghidradbg.exdi.exdi_methods import XTHREADS_PATTERN\n\ndef is_exdi_threads_obj(obj) -> bool:\n    return XTHREADS_PATTERN.fullmatch(obj.path) is not None\n\nif not is_exdi_threads_obj(obj):\n    raise ValueError('expected an ExdiThreadsContainer object')","typeGuard":"def is_exdi_threads_obj(obj) -> bool:\n    from ghidradbg.exdi.exdi_methods import XTHREADS_PATTERN\n    return bool(getattr(obj, 'path', None)) and XTHREADS_PATTERN.fullmatch(obj.path) is not None","tryCatchPattern":"try:\n    pid = find_pid_by_obj(obj)\nexcept TypeError as e:\n    if 'is not' in str(e):\n        raise ValueError(f'wrong object type for Exdi pid lookup: {obj}') from e\n    raise","preventionTips":["Only call Exdi helpers when util.is_exdi() is true.","Resolve objects from the ExdiProcesses/ExdiThreads subtrees.","Keep Exdi and native dbgeng dispatch paths separate."],"tags":["exdi","type-guard","pattern-match","ghidra"],"backgroundTag":null,"analyzedSha":"d5f144c24d6bc53c9cbf4448c6d11143e7696206","analyzedAt":"2026-08-14T01:00:57.564Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}