YunaiV/ruoyi-vue-pro · error · IllegalStateException

[createDecodeParser][帧长度异常,length: %d, frameBodyLength: %d]

Error message

[createDecodeParser][帧长度异常,length: %d, frameBodyLength: %d]

What it means

During length-field decoding the codec computes frameBodyLength = readLength(...) + lengthAdjustment and rejects a NEGATIVE result as an illegal frame. A negative value means the decoded length field plus the configured adjustment underflows int — a malformed/malicious frame, a wrong lengthFieldOffset/Length (bytes misread), wrong byte order, or a badly-set negative lengthAdjustment.

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:81

    @Override
    public RecordParser createDecodeParser(Handler<Buffer> handler) {
        // 创建状态机:先读取头部,再读取消息体
        RecordParser parser = RecordParser.newFixed(headerLength);
        parser.maxRecordSize(MAX_FRAME_LENGTH); // 设置最大记录大小,防止 DoS 攻击
        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);

View on GitHub (pinned to 0418084e22)

Solutions

  1. Verify lengthFieldOffset, lengthFieldLength, and lengthAdjustment against the device's wire-format datasheet (capture a known-good frame with Wireshark and decode by hand).
  2. Check byte order / signedness: readLength uses getUnsignedByte/getUnsignedShort/getInt — getInt is signed, so values > 2^31 appear negative; use a smaller field or guard the upper bit.
  3. If lengthAdjustment is intentional, recompute it: adjustment = (bytes-after-length-field not counted in length) - (length-field-value offset).
  4. Add an upper-bound check (frameBodyLength > MAX_FRAME_LENGTH) in addition to the negative check for robustness.
Defensive patterns

Strategy: validation

Validate before calling

// validate codec params against the protocol spec at construction time
if (lengthFieldLength != 1 && lengthFieldLength != 2 && lengthFieldLength != 4) {
    throw new IllegalArgumentException("lengthFieldLength 必须是 1、2 或 4");
}
if (lengthFieldOffset < 0) {
    throw new IllegalArgumentException("lengthFieldOffset 不能为负");
}
// and bound the decoded length at runtime (see exampleFix in enriched)

Prevention

When it happens

Trigger: Device sends a length field whose decoded value + lengthAdjustment < 0; lengthFieldOffset/Length wrong so unrelated header bytes are interpreted as the length; lengthAdjustment set to a large negative number; signed vs unsigned misinterpretation; malicious oversized length field that wraps.

Common situations: Codec parameters (lengthFieldOffset, lengthFieldLength, lengthAdjustment) do not match the device protocol spec; device uses a length field that includes its own header bytes but adjustment wasn't set; endian mismatch.

Related errors


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