TooTallNate/Java-WebSocket · error · InvalidFrameException

Continuous frame cannot have RSV1, RSV2 or RSV3 set

Error message

Continuous frame cannot have RSV1, RSV2 or RSV3 set

What it means

PerMessageDeflateExtension.isFrameValid enforces RFC 7692 fragmentation rules: RSV1 may only be set on the first fragment of a compressed message, and RSV2/RSV3 are never allowed. When a continuous (non-first) frame carries any RSV bit, the extension rejects it with this InvalidFrameException to prevent malformed compressed messages from entering the decompression path.

Solutions

  1. Fix the peer so it only sets RSV1 on the first frame of a compressed message and leaves RSV bits unset on continuation frames.
  2. Verify the negotiated extension is permessage-deflate on both sides; if you don't intend compression, exclude the extension from the negotiated extensions so RSV1 semantics don't apply.
  3. If you control frame construction, build continuation frames with rsv1/rsv2/rsv3 = false.
  4. Capture the raw frames (e.g. with a proxy or packet capture) to confirm which RSV bits the peer sets before blaming this library.

Example fix

// before: building continuation frames with compression flag re-applied
Framedata cont = new FramedataImpl1(PartialMessageOpcode);
cont.setRSV1(true); // invalid on continuation

// after: RSV bits only on the first fragment
Framedata cont = new FramedataImpl1(Opcode.CONTINUOUS);
cont.setRSV1(false);
Defensive patterns

Strategy: validation

Validate before calling

// before accepting/creating a continuation frame
if (frame.getOpcode() == Opcode.CONTINUOUS && (frame.isRSV1() || frame.isRSV2() || frame.isRSV3())) {
    throw new IllegalArgumentException("RSV bits must not be set on continuation frames");
}

Prevention

When it happens

Trigger: A WebSocket message is fragmented and a continuation frame (opcode 0) arrives with RSV1, RSV2, or RSV3 set in its header. Happens when a peer incorrectly re-sets the permessage-deflate RSV1 bit on each fragment, or sends garbage control bits on continuation frames.

Common situations: Interoperating with a non-conformant WebSocket client/server that marks every fragment as compressed; hand-rolled WebSocket frame implementations; proxies or middleware that rewrite frame headers and accidentally preserve or set RSV bits on continuation frames.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at src/main/java/org/java_websocket/extensions/permessage_deflate/PerMessageDeflateExtension.java:192

   *
   * <p>IMPORTANT: This API must be called on the class instance used by the library, NOT on the
   * instance which was handed to the library! To get this class instance, retrieve it from the
   * library e.g. via ((Draft_6455) webSocketClient.getConnection().getDraft()).getExtension().
   * Make sure to apply class instance checks, as the extension may not have been negotiated.
   *
   * @return the overall compression ratio of all incoming and outgoing payloads
   */
  public double getCompressionRatio() {
    double decompressed = decompressedBytes;
    return decompressed > 0 ? compressedBytes / decompressed : 1;
  }

  @Override
  public void isFrameValid(Framedata inputFrame) throws InvalidDataException {
    // RFC 7692: RSV1 may only be set for the first fragment of a message
    if (inputFrame instanceof ContinuousFrame
        && (inputFrame.isRSV1() || inputFrame.isRSV2() || inputFrame.isRSV3())) {
      throw new InvalidFrameException("Continuous frame cannot have RSV1, RSV2 or RSV3 set");
    }
    super.isFrameValid(inputFrame);
  }

  @Override
  public void decodeFrame(Framedata inputFrame) throws InvalidDataException {
    // RFC 7692: PMCEs operate only on data messages.
    if (!(inputFrame instanceof DataFrame)) {
      return;
    }

    // decompression is only applicable if it was started on the first fragment
    if (!isDecompressing && inputFrame instanceof ContinuousFrame) {
      return;
    }

    // check the RFC 7692 compression marker RSV1 whether to start decompressing
    if (inputFrame.isRSV1()) {

View on GitHub (pinned to afeacbf8c0)