NationalSecurityAgency/ghidra · error · TraceRmiError

Could not send request

Error message

Could not send request

What it means

Thrown when invoking an asynchronous remote method and sendDelimited fails with an IOException while writing the request to the socket. The IOException is wrapped in TraceRmiError. It indicates the output side of the connection is broken (closed stream, reset socket, broken pipe).

Source

Thrown at Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/service/tracermi/TraceRmiHandler.java:1281

				.addAllArguments(
					arguments.entrySet().stream().map(TraceRmiHandler::makeArgument).toList());
		DefaultRemoteAsyncResult result;
		if (open != null) {
			result = new DefaultRemoteAsyncResult(open);
			invoke.setOid(open.doId.toDomObjId());
		}
		else {
			result = new DefaultRemoteAsyncResult();
		}
		req.setXrequestInvokeMethod(invoke);
		synchronized (xReqQueue) {
			xReqQueue.offer(result);
			synchronized (out) {
				try {
					sendDelimited(out, req.build(), dbgSeq++);
				}
				catch (IOException e) {
					throw new TraceRmiError("Could not send request", e);
				}
			}
			return result;
		}
	}

	@Override
	public long getLastSnapshot(Trace trace) {
		OpenTrace byTrace = openTraces.getByTrace(trace);
		if (byTrace == null) {
			throw new NoSuchElementException();
		}
		TraceSnapshot lastSnapshot = byTrace.lastSnapshot;
		if (lastSnapshot == null) {
			return 0;
		}
		return lastSnapshot.getKey();
	}

View on GitHub (pinned to d5f144c24d)

Solutions

  1. Check the connection/handler is still alive (not disposed) before invoking; reconnect if closed.
  2. Inspect logs for the peer's reason for closing the socket.
  3. Catch TraceRmiError around invokeAsync and re-establish the connection, then retry idempotent operations.
  4. Avoid invoking methods after explicitly disposing the connection.

Example fix

// before
method.invokeAsync(args).toCompletableFuture().join();

// after
try {
    method.invokeAsync(args).toCompletableFuture().join();
} catch (TraceRmiError e) {
    // connection lost; reconnect and retry if idempotent
    reconnect();
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (handler.isDisposed() || socket.isClosed()) {
    throw new IllegalStateException("connection closed; cannot send");
}

Try / catch

try {
    method.invokeAsync(args).toCompletableFuture().join();
} catch (TraceRmiError e) {
    // output broken; reconnect then retry idempotent ops
}

Prevention

When it happens

Trigger: Calling a RemoteMethod.invokeAsync(...) after the server closed the connection; the socket was disposed; the peer crashed mid-session; network drop severed the write path.

Common situations: Server/frontend process exited; connection timed out and was closed; long-running session lost network; invoking methods on a disposed handler.

Related errors


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