NationalSecurityAgency/ghidra · error · RuntimeException

Failed to read memory

Error message

Failed to read memory

What it means

Ghidra DebuggerReadsMemoryTrait wraps the result of target.readMemoryAsync(sel, monitor).get(). If the future completes exceptionally (ExecutionException) or the waiting thread is interrupted (InterruptedException), the task throws RuntimeException("Failed to read memory", e). This typically reflects a backend/target communication failure during a memory-read action.

Source

Thrown at Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/DebuggerReadsMemoryTrait.java:89

			if (!current.isAliveAndReadsPresent()) {
				return;
			}
			AddressSetView selection = getSelection();
			if (selection == null || selection.isEmpty()) {
				selection = visible;
			}
			final AddressSetView sel = selection;
			Target target = current.getTarget();

			TargetActionTask.executeTask(tool, new Task(NAME, true, true, false) {
				@Override
				public void run(TaskMonitor monitor) throws CancelledException {
					target.invalidateMemoryCaches();
					try {
						target.readMemoryAsync(sel, monitor).get();
					}
					catch (InterruptedException | ExecutionException e) {
						throw new RuntimeException("Failed to read memory", e);
					}
					memoryWasRead(sel);
				}
			});
		}

		@Override
		public boolean isEnabledForContext(ActionContext context) {
			return current.isAliveAndReadsPresent();
		}

		public void updateEnabled(ActionContext context) {
			setEnabled(isEnabledForContext(context));
		}
	}

	protected class ForReadsTraceListener extends TraceDomainObjectListener {
		public ForReadsTraceListener() {

View on GitHub (pinned to d5f144c24d)

Solutions

  1. Confirm the target is still alive and connected before issuing the read (current.isAliveAndReadsPresent()).
  2. Narrow the selection to known-mapped, accessible memory regions.
  3. Reattach/reconnect to the target if the transport dropped, then retry.
  4. Catch RuntimeException around the action and inspect getCause() to distinguish cancellation from a transport error.

Example fix

// before
target.readMemoryAsync(sel, monitor).get(); // propagates as RuntimeException("Failed to read memory")

// after
try {
    target.readMemoryAsync(sel, monitor).get();
} catch (ExecutionException ee) {
    Msg.error(this, "Target read failed: " + ee.getCause());
} catch (InterruptedException ie) {
    Thread.currentThread().interrupt();
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (!current.isAliveAndReadsPresent()) {
    // target not usable for reads; abort the action
    return;
}

Try / catch

try {
    target.readMemoryAsync(sel, monitor).get();
} catch (ExecutionException ee) {
    Msg.error(this, "read failed", ee.getCause());
} catch (InterruptedException ie) {
    Thread.currentThread().interrupt();
}

Prevention

When it happens

Trigger: Invoking the read-memory action on a selection when the debug target's readMemoryAsync fails — e.g., the target process died, the connection dropped, the address range is unreadable, or the task was cancelled/interrupted.

Common situations: Target process terminated mid-read; debugger backend connection lost; reading an address range not mapped/accessible; user cancellation racing with the read.

Related errors


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