{"record":{"id":"4e3674f5ac3cb2ac","repo":"NationalSecurityAgency/ghidra","slug":"could-not-send-request","errorCode":null,"errorMessage":"Could not send request","messagePattern":"Could not send request","errorType":"exception","errorClass":"TraceRmiError","httpStatus":null,"severity":"error","filePath":"Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/service/tracermi/TraceRmiHandler.java","lineNumber":1281,"sourceCode":"\t\t\t\t.addAllArguments(\n\t\t\t\t\targuments.entrySet().stream().map(TraceRmiHandler::makeArgument).toList());\n\t\tDefaultRemoteAsyncResult result;\n\t\tif (open != null) {\n\t\t\tresult = new DefaultRemoteAsyncResult(open);\n\t\t\tinvoke.setOid(open.doId.toDomObjId());\n\t\t}\n\t\telse {\n\t\t\tresult = new DefaultRemoteAsyncResult();\n\t\t}\n\t\treq.setXrequestInvokeMethod(invoke);\n\t\tsynchronized (xReqQueue) {\n\t\t\txReqQueue.offer(result);\n\t\t\tsynchronized (out) {\n\t\t\t\ttry {\n\t\t\t\t\tsendDelimited(out, req.build(), dbgSeq++);\n\t\t\t\t}\n\t\t\t\tcatch (IOException e) {\n\t\t\t\t\tthrow new TraceRmiError(\"Could not send request\", e);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\t}\n\n\t@Override\n\tpublic long getLastSnapshot(Trace trace) {\n\t\tOpenTrace byTrace = openTraces.getByTrace(trace);\n\t\tif (byTrace == null) {\n\t\t\tthrow new NoSuchElementException();\n\t\t}\n\t\tTraceSnapshot lastSnapshot = byTrace.lastSnapshot;\n\t\tif (lastSnapshot == null) {\n\t\t\treturn 0;\n\t\t}\n\t\treturn lastSnapshot.getKey();\n\t}","sourceCodeStart":1263,"sourceCodeEnd":1299,"githubUrl":"https://github.com/NationalSecurityAgency/ghidra/blob/d5f144c24d6bc53c9cbf4448c6d11143e7696206/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/service/tracermi/TraceRmiHandler.java#L1263-L1299","documentation":"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).","triggerScenarios":"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.","commonSituations":"Server/frontend process exited; connection timed out and was closed; long-running session lost network; invoking methods on a disposed handler.","solutions":["Check the connection/handler is still alive (not disposed) before invoking; reconnect if closed.","Inspect logs for the peer's reason for closing the socket.","Catch TraceRmiError around invokeAsync and re-establish the connection, then retry idempotent operations.","Avoid invoking methods after explicitly disposing the connection."],"exampleFix":"// before\nmethod.invokeAsync(args).toCompletableFuture().join();\n\n// after\ntry {\n    method.invokeAsync(args).toCompletableFuture().join();\n} catch (TraceRmiError e) {\n    // connection lost; reconnect and retry if idempotent\n    reconnect();\n}","handlingStrategy":"try-catch","validationCode":"if (handler.isDisposed() || socket.isClosed()) {\n    throw new IllegalStateException(\"connection closed; cannot send\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    method.invokeAsync(args).toCompletableFuture().join();\n} catch (TraceRmiError e) {\n    // output broken; reconnect then retry idempotent ops\n}","preventionTips":["Check the handler/connection is alive before invoking remote methods.","Do not invoke methods after disposing the connection.","Catch TraceRmiError around async invocations and reconnect for transient failures."],"tags":["trace-rmi","connection","network","async-invoke"],"backgroundTag":null,"analyzedSha":"d5f144c24d6bc53c9cbf4448c6d11143e7696206","analyzedAt":"2026-08-14T01:00:57.564Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}