oracle/graal · error · IOException
handshake failed - connection prematurely closed
Error message
handshake failed - connection prematurely closed
What it means
Thrown by HandshakeController.handshake when the socket stream returns EOF (read() < 0) while the 14-byte 'JDWP-Handshake' greeting is still incomplete. The peer closed the connection partway through (or immediately after connecting) after sending fewer than 14 bytes, so the agent closes the socket and fails the handshake.
Source
Thrown at espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/HandshakeController.java:121
/**
* Handshake with the debugger.
*/
static boolean handshake(Socket s) throws IOException {
byte[] hello = JDWP_HANDSHAKE.getBytes(StandardCharsets.UTF_8);
byte[] b = new byte[hello.length];
int received = 0;
while (received < hello.length) {
int n;
try {
n = s.getInputStream().read(b, received, hello.length - received);
} catch (SocketTimeoutException x) {
throw new IOException("handshake timeout");
}
if (n < 0) {
s.close();
throw new IOException("handshake failed - connection prematurely closed");
}
received += n;
}
for (int i = 0; i < hello.length; i++) {
if (b[i] != hello[i]) {
throw new IOException("handshake failed - unrecognized message from the debugger");
}
}
// handshake received, so return the gesture to establish the jdwp transport
s.getOutputStream().write(hello);
return true;
}
}
View on GitHub (pinned to a66e9ccd1d)
Solutions
- Confirm the peer is a real JDWP client and stays connected through the handshake
- Exclude the JDWP port from TCP health checks and port scans
- Check intermediary idle-timeout/reset behavior between debugger and target JVM
Defensive patterns
Strategy: try-catch
Try / catch
catch (IOException e) when message contains 'prematurely closed': treat as a non-debugger probe; close cleanly and continue the accept loop.
Prevention
- Configure load balancers/Docker health checks to a dedicated port
- Watch for intermediaries with aggressive idle timeouts between debugger and target
When it happens
Trigger: A client connects, sends a partial greeting (or nothing), then closes the socket; also middleboxes that accept then reset connections, or a debugger killed between connect and handshake.
Common situations: Docker/Kubernetes port checks that open and immediately close connections; SYN-proxying firewalls; an IDE attaching and being cancelled mid-attach; keepalive/timeout settings on an intermediary killing idle new connections.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- Unable to handshake with debugger
- handshake timeout
- handshake failed - unrecognized message from the debugger
- Invalid JDWP option value: {key} can be only 'y' or 'n'.
- JDWP options must be a comma separated list of key=value pai
AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14).
Data as JSON: /api/errors/42d3d7b4703c0cd8.
Report an issue: GitHub.