NationalSecurityAgency/ghidra · error · ValueError
Object/proxy has neither id nor path!: {}
Error message
Object/proxy has neither id nor path!: {} What it means
Raised by Client._write_obj_desc() when serializing an object reference and none of the recognized cases matched: the value is not an int, str, DetachedObject, a TraceObject with an int id, a resolved RemoteResult id, or a TraceObject with a str path. Essentially the object carries neither a usable id nor a usable path, so it cannot be written to the wire.
Source
Thrown at Ghidra/Debug/Debugger-rmi-trace/src/main/py/src/ghidratrace/client.py:781
return Lifespan(msg.min, msg.max)
@staticmethod
def _write_obj_spec(to: bufs.ObjSpec, obj: Union[
str, int, DetachedObject, TraceObject]) -> None:
if isinstance(obj, int):
to.id = obj
elif isinstance(obj, str):
to.path.path = obj
elif isinstance(obj, DetachedObject):
to.id = obj.id
elif isinstance(obj.id, int):
to.id = obj.id
elif isinstance(obj.id, RemoteResult) and obj.id.done():
to.id = obj.id.result()
elif isinstance(obj.path, str):
to.path.path = obj.path
else:
raise ValueError(
"Object/proxy has neither id nor path!: {}".format(obj))
@staticmethod
def _read_obj_desc(msg: bufs.ObjDesc) -> DetachedObject:
return DetachedObject(msg.id, msg.path.path)
@staticmethod
def _write_value(to: bufs.Value, value: Any,
schema: Optional[sch.Schema] = None) -> None:
if value is None:
to.null_value.SetInParent()
return
elif isinstance(value, bool):
to.bool_value = value
return
elif isinstance(value, int):
if schema == sch.BYTE:
to.byte_value = valueView on GitHub (pinned to d5f144c24d)
Solutions
- Ensure the object has at least one concrete identifier (resolved id or path) before it is sent.
- Resolve any pending Future id first (call .result()) or use from_path() to guarantee a path.
- Construct objects only via the factory helpers (proxy_object/from_id/from_path) rather than directly.
Example fix
// before obj = trace.proxy_object(id=fut) # fut is an unresolved Future // after obj = trace.proxy_object(id=fut.result()) # resolve first, or pass a path
Defensive patterns
Strategy: validation
Validate before calling
def obj_has_ref(o) -> bool:
return (getattr(o, 'id', None) is not None and not isinstance(o.id, type(None))) \
or getattr(getattr(o, 'path', None), 'path', None)
if not obj_has_ref(obj):
raise ValueError('object has neither resolved id nor path') Type guard
def is_writable_obj_ref(o) -> bool:
import concurrent.futures as cf
oid = getattr(o, 'id', None)
if isinstance(oid, int): return True
if isinstance(oid, cf.Future) and oid.done(): return True
if isinstance(getattr(o, 'path', None), str) or getattr(getattr(o,'path',None),'path',None): return True
return False Prevention
- Resolve Future ids before sending.
- Always construct objects via the factory helpers.
When it happens
Trigger: A TraceObject whose id is an unresolved Future and whose path is None; a DetachedObject constructed with non-int id and non-str path; passing an arbitrary object where an object reference was expected.
Common situations: Using a TraceObject before its id/path has been resolved (e.g. a Future that has not completed), version skew, or hand-built mock objects in tests.
Related errors
- Cannot write Value: {schema}, {value}, {type(value)}
- Method requires trace binding
- Must have id or path
- Cannot convert: {value:r}
- Could not read value: {}
AI-assisted analysis of NationalSecurityAgency/ghidra@d5f144c24d (2026-08-14).
Data as JSON: /api/errors/abaa3c87b67694ae.
Report an issue: GitHub.