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
- Verify lengthFieldOffset, lengthFieldLength, and lengthAdjustment against the device's wire-format datasheet (capture a known-good frame with Wireshark and decode by hand).
- 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.
- If lengthAdjustment is intentional, recompute it: adjustment = (bytes-after-length-field not counted in length) - (length-field-value offset).
- 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
- Capture a known-good frame and decode the length field by hand to lock down offset/length/adjustment.
- Remember getInt (4-byte) is SIGNED — guard the high bit or use a 2-byte field for large frames.
- Add both a lower bound (>=0, already present) and an upper bound (<= MAX_FRAME_LENGTH) check.
- Treat a persistent negative-length error as a protocol-spec mismatch, not a device bug, until verified.
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
- [createDecodeParser][消息体不能为空]
- 数据长度 %d 超过固定长度 %d
- [createDecodeParser][解析异常]
- 不支持的长度字段长度: {}
- [createDecodeParser][解析异常]
AI-assisted analysis of YunaiV/ruoyi-vue-pro@0418084e22 (2026-08-14).
Data as JSON: /api/errors/049bbccd4a5ec931.
Report an issue: GitHub.