TooTallNate/Java-WebSocket · error · InvalidFrameException

closecode must not be sent over the wire

Error message

closecode must not be sent over the wire: {code}

What it means

This is the final wire-safety check in CloseFrame.isValid: certain codes must never appear in a close frame sent over the network — ABNORMAL_CLOSE (1006), TLS_ERROR (1015), NOCODE (0), codes outside 1000-4999, and the reserved 1004. Violating this throws InvalidFrameException with the offending code embedded in the message.

Solutions

  1. Never send 1006/1015/0/1004 — these are generated internally by the library to signal local conditions.
  2. Map desired meanings to allowed codes: 1000 normal, 1001 going away, 1011 server error, 4000-4999 app-defined.
  3. Add a pre-send guard in your code that rejects codes in the forbidden set.
  4. Inspect the message's trailing number to identify which illegal code was used.

Example fix

// before
webSocket.close(1006, "connection dropped"); // 1006 never goes on the wire

// after
webSocket.close(1001, "connection dropped");
Defensive patterns

Strategy: validation

Validate before calling

static final Set<Integer> FORBIDDEN = Set.of(1004, 1005, 1006, 1015, 0);
static boolean canSendCode(int code) {
    return !FORBIDDEN.contains(code) && code >= 1000 && code <= 4999;
}

Try / catch

try {
    webSocket.close(code, reason);
} catch (InvalidFrameException e) {
    logger.error("illegal close code attempted: {}", e.getMessage());
    webSocket.close(1001); // safe substitute
}

Prevention

When it happens

Trigger: Constructing or sending a CloseFrame whose code is 1006, 1015, 0, 1004, < 1000, or > 4999; isValid() runs during frame construction/send (also invoked from WebSocket.close).

Common situations: Trying to echo back a 1006 abnormal closure received from the peer (1006 is never a wire code); forwarding I/O error codes like -1 or 0; using codes above 4999 for app semantics.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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

Appendix: source

Thrown at src/main/java/org/java_websocket/framing/CloseFrame.java:241

  }

  @Override
  public void isValid() throws InvalidDataException {
    super.isValid();
    if (code == CloseFrame.NO_UTF8 && reason.isEmpty()) {
      throw new InvalidDataException(CloseFrame.NO_UTF8, "Received text is no valid utf8 string!");
    }
    if (code == CloseFrame.NOCODE && 0 < reason.length()) {
      throw new InvalidDataException(PROTOCOL_ERROR,
          "A close frame must have a closecode if it has a reason");
    }
    //Intentional check for code != CloseFrame.TLS_ERROR just to make sure even if the code earlier changes
    if ((code > CloseFrame.TLS_ERROR && code < 3000)) {
      throw new InvalidDataException(PROTOCOL_ERROR, "Trying to send an illegal close code!");
    }
    if (code == CloseFrame.ABNORMAL_CLOSE || code == CloseFrame.TLS_ERROR
        || code == CloseFrame.NOCODE || code > 4999 || code < 1000 || code == 1004) {
      throw new InvalidFrameException("closecode must not be sent over the wire: " + code);
    }
  }

  @Override
  public void setPayload(ByteBuffer payload) {
    code = CloseFrame.NOCODE;
    reason = "";
    payload.mark();
    if (payload.remaining() == 0) {
      code = CloseFrame.NORMAL;
    } else if (payload.remaining() == 1) {
      code = CloseFrame.PROTOCOL_ERROR;
    } else {
      if (payload.remaining() >= 2) {
        ByteBuffer bb = ByteBuffer.allocate(4);
        bb.position(2);
        bb.putShort(payload.getShort());
        bb.position(0);

View on GitHub (pinned to afeacbf8c0)