TooTallNate/Java-WebSocket · error · IllegalArgumentException

parameter must not be null

Error message

parameter must not be null

What it means

The SSLSocketChannel2 constructor validates that the SocketChannel, SSLEngine and ExecutorService are all non-null and throws IllegalArgumentException('parameter must not be null') otherwise. It exists so the SSL wrapper fails fast instead of producing a NullPointerException deep inside the I/O loop.

Solutions

  1. Create the SSLEngine via a properly configured SSLContext before constructing the channel
  2. Pass a running ExecutorService (e.g. Executors.newCachedThreadPool()) — never null
  3. Add null checks/guards before calling the constructor and fail with a descriptive message

Example fix

// before
new SSLSocketChannel2(channel, null, exec, key); // NPE-prone engine setup
// after
SSLContext ctx = buildSslContext(keystore, password); // throws early if config is bad
SSLEngine engine = ctx.createSSLEngine();
engine.setUseClientMode(false);
new SSLSocketChannel2(channel, engine, Executors.newCachedThreadPool(), key);
Defensive patterns

Strategy: validation

Validate before calling

if (channel == null || sslEngine == null || exec == null) {
  throw new IllegalArgumentException("SSLSocketChannel2 requires channel, sslEngine and exec");
}

Type guard

boolean ready = channel != null && sslEngine != null && exec != null;
if (!ready) { failFast("SSL channel dependencies missing"); }

Try / catch

try { new SSLSocketChannel2(ch, engine, exec, key); } catch (IllegalArgumentException e) { log.error("SSL channel init failed: {}", e.getMessage()); throw e; }

Prevention

When it happens

Trigger: Calling new SSLSocketChannel2(channel, sslEngine, exec, key) with any of channel, sslEngine or exec null — e.g. SSLContext initialization failed silently, the accept returned a null channel, or the server's executor was not initialized.

Common situations: Misconfigured keystore/truststore leading to a null SSLEngine; forgetting to set the worker ExecutorService on a custom WebSocketServer; wiring the channel manually instead of via WebSocketServer factory methods.

Related errors


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

Appendix: source

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

   * used to set interestOP SelectionKey.OP_WRITE for the underlying channel
   */
  protected SelectionKey selectionKey;

  protected SSLEngine sslEngine;
  protected SSLEngineResult readEngineResult;
  protected SSLEngineResult writeEngineResult;

  /**
   * Should be used to count the buffer allocations. But because of #190 where
   * HandshakeStatus.FINISHED is not properly returned by nio wrap/unwrap this variable is used to
   * check whether {@link #createBuffers(SSLSession)} needs to be called.
   **/
  protected int bufferallocations = 0;

  public SSLSocketChannel2(SocketChannel channel, SSLEngine sslEngine, ExecutorService exec,
      SelectionKey key) throws IOException {
    if (channel == null || sslEngine == null || exec == null) {
      throw new IllegalArgumentException("parameter must not be null");
    }

    this.socketChannel = channel;
    this.sslEngine = sslEngine;
    this.exec = exec;

    readEngineResult = writeEngineResult = new SSLEngineResult(Status.BUFFER_UNDERFLOW,
        sslEngine.getHandshakeStatus(), 0, 0); // init to prevent NPEs

    tasks = new ArrayList<Future<?>>(3);
    if (key != null) {
      key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
      this.selectionKey = key;
    }
    createBuffers(sslEngine.getSession());
    // kick off handshake
    socketChannel.write(wrap(emptybuffer));// initializes res
    processHandshake(false);

View on GitHub (pinned to afeacbf8c0)