TooTallNate/Java-WebSocket · error · EOFException

Connection is closed

Error message

Connection is closed

What it means

SSLSocketChannel2.write() throws EOFException when, after attempting to wrap and write data, the SSLEngine reports Status.CLOSED — i.e. the TLS session has already been closed (close_notify received or engine closed) and no more application data can be sent. The library converts this TLS state into EOFException so callers stop writing.

Solutions

  1. Check websocket.isOpen() (or ReadyState == OPEN) before sending.
  2. Route all sends through a single thread or synchronize access so writes cannot race with close.
  3. Catch WebsocketNotConnectedException/EOFException around send() and drop or requeue the message.
  4. Reconnect via WebSocketClient.reconnect() if the message must be delivered after an unexpected close.

Example fix

// before
conn.send(payload);
// after
if (conn.isOpen()) {
  conn.send(payload);
} else {
  queueForResend(payload);
}
Defensive patterns

Strategy: type-guard

Validate before calling

if (!conn.isOpen()) { /* skip or queue send */ }

Type guard

boolean canSend = conn != null && conn.isOpen() && conn.getReadyState().equals(ReadyState.OPEN);

Try / catch

try { conn.send(data); } catch (WebsocketNotConnectedException | EOFException e) { queueForResend(data); }

Prevention

When it happens

Trigger: Calling write()/send() on a WebSocket whose SSL engine has closed: after the peer sent close_notify, after closeConnection was initiated, or a concurrent write raced with the close handshake.

Common situations: Sending a message from another thread while the connection is closing; server closed the connection but the client queue still has pending frames; missed the onClose callback before issuing a send.

Related errors


AI-assisted analysis of TooTallNate/Java-WebSocket@afeacbf8c0 (2026-09-09). Data as JSON: /api/errors/c3994cd5a9ed7d24. Report an issue: GitHub.

Appendix: source

Thrown at src/main/java/org/java_websocket/SSLSocketChannel2.java:285

    inCrypt.rewind();
    inCrypt.flip();
    outCrypt.rewind();
    outCrypt.flip();
    bufferallocations++;
  }

  public int write(ByteBuffer src) throws IOException {
    if (!isHandShakeComplete()) {
      processHandshake(false);
      return 0;
    }
    // assert(bufferallocations > 1); // see #190
    // if(bufferallocations <= 1) {
    //   createBuffers(sslEngine.getSession());
    // }
    int num = socketChannel.write(wrap(src));
    if (writeEngineResult.getStatus() == SSLEngineResult.Status.CLOSED) {
      throw new EOFException("Connection is closed");
    }
    return num;

  }

  /**
   * Blocks when in blocking mode until at least one byte has been decoded.<br> When not in blocking
   * mode 0 may be returned.
   *
   * @return the number of bytes read.
   **/
  public int read(ByteBuffer dst) throws IOException {
    tryRestoreCryptedData();
    while (true) {
      if (!dst.hasRemaining()) {
        return 0;
      }
      if (!isHandShakeComplete()) {

View on GitHub (pinned to afeacbf8c0)