{"record":{"id":"4afb5f8ffba33da9","repo":"NationalSecurityAgency/ghidra","slug":"object-is-not-a-module","errorCode":null,"errorMessage":"{object} is not a Module","messagePattern":"(.+?) is not a Module","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"Ghidra/Debug/Debugger-agent-gdb/src/main/py/src/ghidragdb/methods.py","lineNumber":146,"sourceCode":"    return find_inf_by_pattern(object, THREADS_PATTERN, \"a ThreadContainer\")\n\n\ndef find_inf_by_mem_obj(object: TraceObject) -> gdb.Inferior:\n    return find_inf_by_pattern(object, MEMORY_PATTERN, \"a Memory\")\n\n\ndef find_inf_by_modules_obj(object: TraceObject) -> gdb.Inferior:\n    return find_inf_by_pattern(object, MODULES_PATTERN, \"a ModuleContainer\")\n\n\ndef find_inf_by_mod_obj(object: TraceObject) -> gdb.Inferior:\n    return find_inf_by_pattern(object, MODULE_PATTERN, \"a Module\")\n\n\ndef find_module_name_by_mod_obj(object: TraceObject) -> str:\n    mat = MODULE_PATTERN.fullmatch(object.path)\n    if mat is None:\n        raise TypeError(f\"{object} is not a Module\")\n    return mat['modname']\n\n\ndef find_thread_by_num(inf: gdb.Inferior, tnum: int) -> gdb.InferiorThread:\n    for t in inf.threads():\n        if t.num == tnum:\n            return t\n    raise KeyError(f\"Inferiors[{inf.num}].Threads[{tnum}] does not exist\")\n\n\ndef find_thread_by_pattern(pattern: re.Pattern, object: TraceObject,\n                           err_msg: str) -> gdb.InferiorThread:\n    mat = pattern.fullmatch(object.path)\n    if mat is None:\n        raise TypeError(f\"{object} is not {err_msg}\")\n    infnum = int(mat['infnum'])\n    tnum = int(mat['tnum'])\n    inf = find_inf_by_num(infnum)","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/NationalSecurityAgency/ghidra/blob/d5f144c24d6bc53c9cbf4448c6d11143e7696206/Ghidra/Debug/Debugger-agent-gdb/src/main/py/src/ghidragdb/methods.py#L128-L164","documentation":"Thrown by find_module_name_by_mod_obj in the Ghidra GDB agent when a TraceObject's path does not fullmatch MODULE_PATTERN (Inferiors[<infnum>].Modules[<modname>]). The agent uses regex matching to derive the module name from the object's path; a non-module object (e.g. a Modules container, a Memory region, or a mistyped/synthetic path) yields no match. It is raised as TypeError because the caller passed an object of the wrong shape.","triggerScenarios":"Calling find_module_name_by_mod_obj with a TraceObject whose .path is anything other than Inferiors[N].Modules[name] — e.g. an Inferiors[N].Modules container, an Inferiors[N] inferior, or a Modules entry created by a code path that did not normalize the path. Typically reached via a method handler that receives a target object from Ghidra and extracts the module name without first validating kind.","commonSituations":"A trace-rpc method bound to a Module schema node receives a sibling object (container or section) because the object was created/inserted at the wrong path; partial trace population where Modules children exist but with malformed keys; cross-version schema drift where MODULE_PATTERN changed but stale objects remain in the trace.","solutions":["Confirm the object's .path is a descendant of Inferiors[N].Modules and contains a [modname] key segment before extracting the name.","Gate the call: use a kind/path predicate (or find_inf_by_mod_obj success) before find_module_name_by_mod_obj so wrong-kind objects never reach it.","Inspect the live TraceObject path at the call site (log object.path) and compare against re.compile pattern MODULE_PATTERN to find the mismatch.","Ensure the trace object was created via the canonical module-insertion code path that emits Inferiors[N].Modules[<modpath>]."],"exampleFix":"// before\nname = find_module_name_by_mod_obj(obj)\n// after\nif MODULE_PATTERN.fullmatch(obj.path) is None:\n    raise ValueError(f\"expected a Module object, got {obj.path}\")\nname = find_module_name_by_mod_obj(obj)","handlingStrategy":"type-guard","validationCode":"import re\n# MODULE_PATTERN imported from ghidragdb.methods\n_IS_MODULE = lambda obj: MODULE_PATTERN.fullmatch(obj.path) is not None\nif not _IS_MODULE(obj):\n    raise ValueError(f\"expected Module object, got {obj.path}\")\nname = find_module_name_by_mod_obj(obj)","typeGuard":"def is_module_obj(obj: TraceObject) -> bool:\n    return MODULE_PATTERN.fullmatch(obj.path) is not None","tryCatchPattern":"try:\n    name = find_module_name_by_mod_obj(obj)\nexcept TypeError:\n    # wrong kind of object; refresh schema binding / log obj.path\n    log.warning(\"not a Module object: %s\", obj.path)\n    raise","preventionTips":["always route objects through the typed find_*_by_obj wrappers","validate object.path against the expected pattern at dispatch boundaries","keep schema node bindings in sync with resolver patterns"],"tags":["ghidra","gdb","trace-rpc","type-error","pattern-match"],"backgroundTag":null,"analyzedSha":"d5f144c24d6bc53c9cbf4448c6d11143e7696206","analyzedAt":"2026-08-14T01:00:57.564Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}