YunaiV/ruoyi-vue-pro · warning · IllegalStateException

[createDecodeParser][消息体不能为空]

Error message

[createDecodeParser][消息体不能为空]

What it means

During length-field decoding, after computing frameBodyLength = readLength(...) + lengthAdjustment, a result of exactly ZERO is rejected as an empty body. This fires when the decoded length field plus adjustment equals zero — the device sent a zero-length body, or lengthAdjustment cancels out a legitimate small length value.

Source

Thrown at yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/codec/length/IotTcpLengthFieldFrameCodec.java:87

        final AtomicReference<Integer> bodyLength = new AtomicReference<>(null); // 消息体长度,null 表示读取头部阶段
        final AtomicReference<Buffer> headerBuffer = new AtomicReference<>(null); // 头部消息

        // 处理读取到的数据
        parser.handler(buffer -> {
            if (bodyLength.get() == null) {
                // 阶段 1: 读取头部,解析长度字段
                headerBuffer.set(buffer.copy());
                int length = readLength(buffer, lengthFieldOffset, lengthFieldLength);
                int frameBodyLength = length + lengthAdjustment;
                // 检查帧长度是否合法
                if (frameBodyLength < 0) {
                    throw new IllegalStateException(String.format(
                            "[createDecodeParser][帧长度异常,length: %d, frameBodyLength: %d]",
                            length, frameBodyLength));
                }
                // 消息体为空,抛出异常
                if (frameBodyLength == 0) {
                    throw new IllegalStateException("[createDecodeParser][消息体不能为空]");
                }

                // 【重要】切换到读取消息体模式
                bodyLength.set(frameBodyLength);
                parser.fixedSizeMode(frameBodyLength);
            } else {
                // 阶段 2: 读取消息体,组装完整帧
                Buffer frame = processFrame(headerBuffer.get(), buffer);
                // 重置状态,准备读取下一帧
                bodyLength.set(null);
                headerBuffer.set(null);
                parser.fixedSizeMode(headerLength);

                // 【重要】处理完整消息
                handler.handle(frame);
            }
        });
        parser.exceptionHandler(ex -> {

View on GitHub (pinned to 0418084e22)

Solutions

  1. Confirm lengthAdjustment matches the protocol — often 0 when the length field already represents the body size.
  2. If zero-body frames are valid in your protocol, relax the codec to handle frameBodyLength==0 (emit an empty body to the handler instead of throwing).
  3. Check the device isn't emitting a malformed length due to a firmware bug (capture traffic).

Example fix

// before: zero-length body throws
if (frameBodyLength == 0) {
    throw new IllegalStateException("[createDecodeParser][消息体不能为空]");
}

// after: allow zero-body frames if your protocol supports them
if (frameBodyLength == 0) {
    Buffer frame = processFrame(headerBuffer.get(), Buffer.buffer());
    bodyLength.set(null);
    headerBuffer.set(null);
    parser.fixedSizeMode(headerLength);
    handler.handle(frame);
    return;
}
Defensive patterns

Strategy: validation

Validate before calling

// confirm lengthAdjustment matches the protocol before deploying
// most commonly 0 when the length field already encodes body size
if (lengthAdjustment != 0) {
    log.warn("lengthAdjustment={}, 确认与设备协议一致", lengthAdjustment);
}

Prevention

When it happens

Trigger: Device sends length=0 with adjustment=0; lengthAdjustment configured to exactly negate a legitimate length value (e.g. length includes header bytes and adjustment subtracts them, netting zero for small frames); device emits a valid heartbeat/keepalive frame with no body that this codec rejects.

Common situations: Misconfigured lengthAdjustment; device protocol legitimately allows zero-body control/heartbeat frames; device firmware bug emitting length=0.

Related errors


AI-assisted analysis of YunaiV/ruoyi-vue-pro@0418084e22 (2026-08-14). Data as JSON: /api/errors/33b4a45c7af46ac2. Report an issue: GitHub.