eclipse-vertx/vert.x · error · java.lang.IllegalStateException

Cannot write an HTTP/2 frame over an HTTP/1.x connection

Error message

Cannot write an HTTP/2 frame over an HTTP/1.x connection

What it means

The stream object embedded in Http1ClientConnection implements writeFrame(type, flags, payload) from the HTTP/2 stream API, but on an HTTP/1.x connection there is no HTTP/2 framing layer, so it unconditionally throws IllegalStateException. This surfaces when code written against the generic Vert.x HTTP API calls writeFrame without checking the protocol.

Source

Thrown at vertx-core/src/main/java/io/vertx/core/http/impl/http1/Http1ClientConnection.java:685

      PromiseInternal<Void> promise = context.promise();
      conn.writeHead(this, request, chunked, buf != null ? ((BufferInternal)buf).getByteBuf() : null, end, connect, promise);
      return promise.future();
    }

    @Override
    public Future<Void> writeChunk(Buffer buff, boolean end) {
      if (buff != null || end) {
        Promise<Void> listener = context.promise();
        conn.writeBuffer(this, buff != null ? ((BufferInternal)buff).getByteBuf() : null, end, listener);
        return listener.future();
      } else {
        throw new IllegalStateException("???");
      }
    }

    @Override
    public Future<Void> writeFrame(int type, int flags, Buffer payload) {
      throw new IllegalStateException("Cannot write an HTTP/2 frame over an HTTP/1.x connection");
    }

    @Override
    public Future<Boolean> cancel() {
      return writeReset(0x8).map(true);
    }

    @Override
    public Future<Void> writeReset(long code) {
      Promise<Void> promise = context.promise();
      EventLoop eventLoop = conn.context.nettyEventLoop();
      if (eventLoop.inEventLoop()) {
        reset(code, promise);
      } else {
        eventLoop.execute(() -> reset(code, promise));
      }
      return promise.future();
    }

View on GitHub (pinned to fb308bd8c3)

Solutions

  1. Check the connection protocol before calling writeFrame: only invoke it when using HTTP/2 (request.version() / HttpVersion.HTTP_2, or connection.isSSL with alpn h2)
  2. Configure the client/server for HTTP/2 (setUseAlpn(true), setHttp2ClearTextEnabled, setProtocolVersion(HTTP_2)) if frames are actually needed
  3. Replace raw frame usage with protocol-neutral APIs (e.g. ping via connection ping if available on HTTP/2 only; otherwise drop the frame logic)

Example fix

// before
request.writeFrame(0x6, 0, pingPayload); // throws on HTTP/1.x
// after
if (request.version() == HttpVersion.HTTP_2) {
  request.writeFrame(0x6, 0, pingPayload);
} else {
  // HTTP/1.x has no frame layer; use app-level keepalive instead
}
Defensive patterns

Strategy: type-guard

Validate before calling

if (request.version() != HttpVersion.HTTP_2) {
  throw new IllegalStateException("writeFrame requires HTTP/2, got " + request.version());
}

Type guard

boolean supportsFrames(HttpClientRequest req) {
  return req.version() == HttpVersion.HTTP_2;
}

Try / catch

try {
  request.writeFrame(type, flags, payload);
} catch (IllegalStateException e) {
  // connection is HTTP/1.x; use protocol-neutral alternative or skip
}

Prevention

When it happens

Trigger: Calling HttpClientRequest/HttpClientStream.writeFrame(int type, int flags, Buffer payload) (e.g. sending a PING, RST_STREAM, or other raw HTTP/2 frame) on a request/connection negotiated as HTTP/1.1 — for example with the default protocol or after ALPN falls back to HTTP/1.x.

Common situations: Using Http2Client-style frame APIs on a client configured with setProtocolVersion(HTTP_1_1) or without HTTP/2 (no alpn/h2c); shared helper code written for HTTP/2 being reused for HTTP/1 connections; downgrade after h2c upgrade negotiation failed.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of eclipse-vertx/vert.x@fb308bd8c3 (2026-09-06). Data as JSON: /api/errors/475439290bfb82df. Report an issue: GitHub.