YunaiV/ruoyi-vue-pro · error · RuntimeException

[createDecodeParser][解析异常]

Error message

[createDecodeParser][解析异常]

What it means

The Vert.x RecordParser.exceptionHandler for the delimiter-based codec rethrows any parser error as RuntimeException. For this codec the realistic trigger is a record exceeding MAX_RECORD_SIZE (64KB): a device streams data without ever emitting the configured delimiter, so the parser buffers past the cap and fires the exception handler.

Solutions

  1. Confirm the configured delimiter (config.delimiter, supporting \n \r \r\n \t or custom) exactly matches the device's frame terminator — capture traffic with Wireshark/tcpdump to verify.
  2. If legitimate frames exceed 64KB, raise MAX_RECORD_SIZE (and ensure memory headroom).
  3. Close or rate-limit the offending connection when the handler fires repeatedly; the exception is thrown on the event loop so add metrics/alerts.
  4. Note: throwing inside exceptionHandler propagates up Vert.x — prefer logging + socket.close() instead of rethrowing to avoid killing the event loop.

Example fix

// before (rethrow can disrupt the Vert.x handler pipeline)
parser.exceptionHandler(ex -> {
    throw new RuntimeException("[createDecodeParser][解析异常]", ex);
});

// after (log + close socket, do not rethrow on event loop)
parser.exceptionHandler(ex -> {
    log.error("[createDecodeParser][解析异常]", ex);
    // signal the owning socket to close
});
Defensive patterns

Strategy: try-catch

Validate before calling

// validate the configured delimiter matches observed traffic before relying on the codec
byte[] expected = parseDelimiter(config.getDelimiter());
if (expected.length == 0) {
    throw new IllegalArgumentException("分隔符不能为空");
}

Try / catch

// log + close the offending socket instead of rethrowing on the Vert.x event loop
parser.exceptionHandler(ex -> {
    log.error("[createDecodeParser][解析异常]", ex);
    // signal connection manager to close this socket
});

Prevention

When it happens

Trigger: Device sends a continuous byte stream that never contains the configured delimiter, crossing 64KB; wrong delimiter configured (device terminates with \n but config says \r\n); a malformed/buggy device flooding garbage; delimiter bytes split across TCP segments in a way that never reassembles (rare with Vert.x).

Common situations: Delimiter mismatch between device firmware and gateway config; device firmware forgot to append the delimiter; malicious device; baud-rate/garbage on a serial-to-TCP converter.

Related errors


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

Appendix: source

Thrown at yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/codec/delimiter/IotTcpDelimiterFrameCodec.java:58

    public IotTcpDelimiterFrameCodec(IotTcpConfig.CodecConfig config) {
        Assert.notBlank(config.getDelimiter(), "delimiter 不能为空");
        this.delimiterBytes = parseDelimiter(config.getDelimiter());
    }

    @Override
    public IotTcpCodecTypeEnum getType() {
        return IotTcpCodecTypeEnum.DELIMITER;
    }

    @Override
    public RecordParser createDecodeParser(Handler<Buffer> handler) {
        RecordParser parser = RecordParser.newDelimited(Buffer.buffer(delimiterBytes));
        parser.maxRecordSize(MAX_RECORD_SIZE); // 设置最大记录大小,防止 DoS 攻击
        // 处理完整消息(不包含分隔符)
        parser.handler(handler);
        parser.exceptionHandler(ex -> {
            throw new RuntimeException("[createDecodeParser][解析异常]", ex);
        });
        return parser;
    }

    @Override
    public Buffer encode(byte[] data) {
        Buffer buffer = Buffer.buffer();
        buffer.appendBytes(data);
        buffer.appendBytes(delimiterBytes);
        return buffer;
    }

    /**
     * 解析分隔符字符串为字节数组
     * <p>
     * 支持转义字符:\n、\r、\r\n、\t
     *
     * @param delimiter 分隔符字符串

View on GitHub (pinned to 0418084e22)