{"record":{"id":"475439290bfb82df","repo":"eclipse-vertx/vert.x","slug":"cannot-write-an-http-2-frame-over-an-http-1-x-conn","errorCode":null,"errorMessage":"Cannot write an HTTP/2 frame over an HTTP/1.x connection","messagePattern":"Cannot write an HTTP/2 frame over an HTTP/1\\.x connection","errorType":"exception","errorClass":"java.lang.IllegalStateException","httpStatus":null,"severity":"error","filePath":"vertx-core/src/main/java/io/vertx/core/http/impl/http1/Http1ClientConnection.java","lineNumber":685,"sourceCode":"      PromiseInternal<Void> promise = context.promise();\n      conn.writeHead(this, request, chunked, buf != null ? ((BufferInternal)buf).getByteBuf() : null, end, connect, promise);\n      return promise.future();\n    }\n\n    @Override\n    public Future<Void> writeChunk(Buffer buff, boolean end) {\n      if (buff != null || end) {\n        Promise<Void> listener = context.promise();\n        conn.writeBuffer(this, buff != null ? ((BufferInternal)buff).getByteBuf() : null, end, listener);\n        return listener.future();\n      } else {\n        throw new IllegalStateException(\"???\");\n      }\n    }\n\n    @Override\n    public Future<Void> writeFrame(int type, int flags, Buffer payload) {\n      throw new IllegalStateException(\"Cannot write an HTTP/2 frame over an HTTP/1.x connection\");\n    }\n\n    @Override\n    public Future<Boolean> cancel() {\n      return writeReset(0x8).map(true);\n    }\n\n    @Override\n    public Future<Void> writeReset(long code) {\n      Promise<Void> promise = context.promise();\n      EventLoop eventLoop = conn.context.nettyEventLoop();\n      if (eventLoop.inEventLoop()) {\n        reset(code, promise);\n      } else {\n        eventLoop.execute(() -> reset(code, promise));\n      }\n      return promise.future();\n    }","sourceCodeStart":667,"sourceCodeEnd":703,"githubUrl":"https://github.com/eclipse-vertx/vert.x/blob/fb308bd8c3f12c79f4ae89bef67fadf6c80d036e/vertx-core/src/main/java/io/vertx/core/http/impl/http1/Http1ClientConnection.java#L667-L703","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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)","Configure the client/server for HTTP/2 (setUseAlpn(true), setHttp2ClearTextEnabled, setProtocolVersion(HTTP_2)) if frames are actually needed","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)"],"exampleFix":"// before\nrequest.writeFrame(0x6, 0, pingPayload); // throws on HTTP/1.x\n// after\nif (request.version() == HttpVersion.HTTP_2) {\n  request.writeFrame(0x6, 0, pingPayload);\n} else {\n  // HTTP/1.x has no frame layer; use app-level keepalive instead\n}","handlingStrategy":"type-guard","validationCode":"if (request.version() != HttpVersion.HTTP_2) {\n  throw new IllegalStateException(\"writeFrame requires HTTP/2, got \" + request.version());\n}","typeGuard":"boolean supportsFrames(HttpClientRequest req) {\n  return req.version() == HttpVersion.HTTP_2;\n}","tryCatchPattern":"try {\n  request.writeFrame(type, flags, payload);\n} catch (IllegalStateException e) {\n  // connection is HTTP/1.x; use protocol-neutral alternative or skip\n}","preventionTips":["Verify the negotiated protocol before using HTTP/2-only APIs","Explicitly configure HTTP/2 (useAlpn, h2c) when frame-level features are required","Keep HTTP/1 and HTTP/2 code paths separate in shared helpers"],"tags":["http","http1","http2","protocol-mismatch"],"backgroundTag":"unsupported-operation","analyzedSha":"fb308bd8c3f12c79f4ae89bef67fadf6c80d036e","analyzedAt":"2026-09-06T11:37:12.241Z","contentChangedAt":"2026-09-06T11:37:12.241Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}