NationalSecurityAgency/ghidra · error · ValueError

Invalid memory state: {}

Error message

Invalid memory state: {}

What it means

Raised by Trace.validate_state() when the supplied memory-state string is not one of 'unknown', 'known', or 'error'. These three states classify a memory range's validity in a Ghidra trace. set_memory_state() calls validate_state() to guard the value before sending it over RMI, so any unrecognized string is rejected before serialization.

Source

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

    def create_overlay_space(self, base: str, name: str) -> Union[
            None, RemoteResult[Any, None]]:
        if name in self.overlays:
            return None
        result = self.client._create_overlay_space(self.id, base, name)
        self.overlays.add(name)
        return result

    def put_bytes(self, address: Address, data: bytes,
                  snap: Optional[int] = None) -> Union[
            int, RemoteResult[Any, int]]:
        if snap is None:
            snap = self.snap()
        return self.client._put_bytes(self.id, snap, address, data)

    @staticmethod
    def validate_state(state) -> None:
        if not state in ('unknown', 'known', 'error'):
            raise ValueError("Invalid memory state: {}".format(state))

    def set_memory_state(self, range: AddressRange, state: str,
                         snap: Optional[int] = None) -> Union[
            None, RemoteResult[Any, None]]:
        if snap is None:
            snap = self.snap()
        return self.client._set_memory_state(self.id, snap, range, state)

    def delete_bytes(self, range: AddressRange, snap:
                     Optional[int] = None) -> Union[
            None, RemoteResult[Any, None]]:
        if snap is None:
            snap = self.snap()
        return self.client._delete_bytes(self.id, snap, range)

    def put_registers(self, space: str, values: Iterable[RegVal],
                      snap: Optional[int] = None) -> Union[
            List[str], RemoteResult[Any, List[str]]]:

View on GitHub (pinned to d5f144c24d)

Solutions

  1. Use the exact literals: 'unknown', 'known', or 'error' (lowercase).
  2. Define a module-level constant or Enum and source every call from it so typos are compile-time caught.
  3. Add an allowlist check: if state not in ('unknown','known','error'): before calling set_memory_state.

Example fix

# before
trace.set_memory_state(rng, 'valid')
# after
VALID_STATES = ('unknown', 'known', 'error')
assert state in VALID_STATES, f'bad state {state!r}'
trace.set_memory_state(rng, state)
Defensive patterns

Strategy: validation

Validate before calling

MEM_STATES = ('unknown', 'known', 'error')
if state not in MEM_STATES:
    raise ValueError(f'Invalid memory state {state!r}; use one of {MEM_STATES}')

Type guard

def is_valid_mem_state(s) -> bool:
    return s in ('unknown', 'known', 'error')

Prevention

When it happens

Trigger: Calling trace.set_memory_state(range, 'cached'), passing 'True'/'TRUE', typos like 'know', or forwarding a state pulled from another tool's vocabulary (e.g. 'dirty', 'valid', 'invalid').

Common situations: Mapping between a debugger backend's memory-state enum and Ghidra's three-state vocabulary; user-typed config; code that assumed boolean or extra states exist.

Related errors


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