YunaiV/ruoyi-vue-pro · error · RuntimeException

二进制消息解码失败: {}

Error message

二进制消息解码失败: {}

What it means

IotBinarySerializer.deserialize wraps any Exception thrown while parsing an incoming byte array — magic-number check, length guard, messageId read, method-length/method read, and parseMessageBody — and rethrows as a RuntimeException. It is distinct from the up-front asserts (Assert.notNull bytes, Assert.isTrue bytes.length >= MIN_MESSAGE_LENGTH) which fail before the try block. So this wrapped error means the packet cleared the minimum-length check but failed structural parsing afterward.

Source

Thrown at yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/serialize/binary/IotBinarySerializer.java:135

                    "消息长度不匹配,期望: " + messageLength + ", 实际: " + buffer.length());

            // 5. 读取消息 ID
            short messageIdLength = buffer.getShort(index);
            index += 2;
            String messageId = buffer.getString(index, index + messageIdLength, StandardCharsets.UTF_8.name());
            index += messageIdLength;

            // 6. 读取方法名
            short methodLength = buffer.getShort(index);
            index += 2;
            String method = buffer.getString(index, index + methodLength, StandardCharsets.UTF_8.name());
            index += methodLength;

            // 7. 解析消息体
            return parseMessageBody(buffer, index, messageType, messageId, method);
        } catch (Exception e) {
            log.error("[decode][二进制消息解码失败,数据长度: {}]", bytes.length, e);
            throw new RuntimeException("二进制消息解码失败: " + e.getMessage(), e);
        }
    }

    /**
     * 快速检测是否为二进制格式
     *
     * @param data 数据
     * @return 是否为二进制格式
     */
    public static boolean isBinaryFormat(byte[] data) {
        return data != null && data.length >= 1 && data[0] == MAGIC_NUMBER;
    }

    private byte determineMessageType(IotDeviceMessage message) {
        if (message.getCode() != null) {
            return RESPONSE;
        }
        return REQUEST;

View on GitHub (pinned to 0418084e22)

Solutions

  1. Call IotBinarySerializer.isBinaryFormat(bytes) (checks data[0] == MAGIC_NUMBER) before deserialize to route packets to the correct serializer.
  2. Inspect the logged cause and bytes.length — the '[decode][二进制消息解码失败' log line prints both.
  3. Validate the packet at the protocol boundary: magic byte, then total length against the declared messageId/method lengths.
  4. Drop or quarantine malformed frames at the UDP handler and log the device address rather than propagating the RuntimeException.

Example fix

// before
IotDeviceMessage msg = binarySerializer.deserialize(bytes); // RuntimeException on junk

// after
if (!IotBinarySerializer.isBinaryFormat(bytes)) {
    // route to JSON deserializer instead
    return jsonSerializer.deserialize(bytes);
}
IotDeviceMessage msg = binarySerializer.deserialize(bytes);
Defensive patterns

Strategy: validation

Validate before calling

// Route by format BEFORE decoding
public IotDeviceMessage safeDeserialize(byte[] bytes, IotMessageSerializer binary, IotMessageSerializer json) {
    if (!IotBinarySerializer.isBinaryFormat(bytes)) {
        return json.deserialize(bytes);
    }
    return binary.deserialize(bytes);
}

Type guard

public static boolean isBinaryFormat(byte[] data) {
    return data != null && data.length >= 1 && data[0] == IotBinarySerializer.MAGIC_NUMBER;
}

Try / catch

try {
    return binarySerializer.deserialize(bytes);
} catch (RuntimeException e) {
    log.warn("[decode][malformed binary frame, len={}]", bytes.length, e);
    return null; // caller drops / dead-letters the datagram
}

Prevention

When it happens

Trigger: Feeding bytes that do not actually start with MAGIC_NUMBER but are long enough; a truncated/corrupt frame (methodLength shorter than remaining buffer, or charset decode failure); a packet from a device speaking a different binary protocol version; network-layer delivering a partial datagram. Note isBinaryFormat(data) is the intended pre-filter and should gate calls to deserialize.

Common situations: A JSON payload mistakenly routed into the binary deserializer; protocol version mismatch between device firmware and gateway; bit flips on lossy transport; sending test/garbage bytes through the binary path.

Related errors


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