oracle/graal · error · IOException

handshake timeout

Error message

handshake timeout

What it means

Thrown by HandshakeController.handshake when the socket read waiting for the JDWP-Handshake gesture raises SocketTimeoutException. The agent reads the 14-byte greeting with a bounded SO_TIMEOUT; if the accepted peer sends nothing within that window, the read times out and handshake setup fails with IOException("handshake timeout").

Solutions

  1. Ensure the debugger actively sends the handshake immediately after connecting
  2. Keep health-check/probe traffic off the JDWP port
  3. Allow only trusted source IPs through the firewall to the debug port
  4. Retry the debugger connection; transient probes will not re-connect
Defensive patterns

Strategy: retry

Try / catch

catch (IOException e) when message contains 'handshake timeout': distinguish from app failure, log, and let the accept loop retry; the debugger can reconnect.

Prevention

When it happens

Trigger: A TCP client connects to the JDWP port but stalls before sending the 'JDWP-Handshake' bytes: half-open connections, firewalls that complete the TCP handshake but drop payload, or an IDE that connects lazily and waits for user action.

Common situations: Port scanners and service-discovery probes (connect then go quiet), NAT/firewall middleboxes, or load balancers doing TCP health checks against the debug port.

Understand the failure class

Related errors


AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14). Data as JSON: /api/errors/3dbeb27480ca982e. Report an issue: GitHub.

Appendix: source

Thrown at espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/HandshakeController.java:117

            currentServerSocket = null;
        }
    }

    /**
     * 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)