apache/seatunnel · error · UnsupportedOperationException

Please invoke DeserializationSchema#deserialize(byte[], Coll

Error message

Please invoke DeserializationSchema#deserialize(byte[], Collector<SeaTunnelRow>) instead.

What it means

A Debezium JSON message can expand into multiple SeaTunnelRows (an UPDATE yields UPDATE_BEFORE + UPDATE_AFTER), so this DeserializationSchema only supports the collector-based entry point deserialize(byte[], Collector<SeaTunnelRow>). The single-row overload deserialize(byte[]) cannot honor that contract and unconditionally throws UnsupportedOperationException.

Source

Thrown at seatunnel-formats/seatunnel-format-json/src/main/java/org/apache/seatunnel/format/json/debezium/DebeziumJsonDeserializationSchema.java:88

    public DebeziumJsonDeserializationSchema(CatalogTable catalogTable, boolean ignoreParseErrors) {
        this(catalogTable, ignoreParseErrors, false);
    }

    public DebeziumJsonDeserializationSchema(
            CatalogTable catalogTable, boolean ignoreParseErrors, boolean debeziumEnabledSchema) {
        this.rowType = catalogTable.getSeaTunnelRowType();
        this.ignoreParseErrors = ignoreParseErrors;
        this.jsonDeserializer =
                new JsonDeserializationSchema(catalogTable, false, ignoreParseErrors);
        this.debeziumRowConverter = new DebeziumRowConverter(rowType);
        this.debeziumEnabledSchema = debeziumEnabledSchema;
        this.tablePath = Optional.of(catalogTable).map(CatalogTable::getTablePath).orElse(null);
    }

    @Override
    public SeaTunnelRow deserialize(byte[] message) throws IOException {
        throw new UnsupportedOperationException(
                "Please invoke DeserializationSchema#deserialize(byte[], Collector<SeaTunnelRow>) instead.");
    }

    @Override
    public void deserialize(byte[] message, Collector<SeaTunnelRow> out) {
        deserializeMessage(message, out, tablePath);
    }

    public void deserializeMessage(
            byte[] message, Collector<SeaTunnelRow> out, TablePath tablePath) {
        if (message == null || message.length == 0) {
            // skip tombstone messages
            return;
        }

        try {
            JsonNode payload = getPayload(jsonDeserializer.deserializeToJsonNode(message));
            parsePayload(out, tablePath, payload);

View on GitHub (pinned to cf67b549a7)

Solutions

  1. Change the call site to deserialize(byte[] message, Collector<SeaTunnelRow> out)
  2. If a synchronous result is needed, pass a collector implementation that buffers rows and read them after the call
  3. Update test harnesses and any engine adapters to the collector-based API

Example fix

// before
SeaTunnelRow row = debeziumDeserializer.deserialize(message);
// after
List<SeaTunnelRow> rows = new ArrayList<>();
deziumDeserializer.deserialize(message, new Collector<SeaTunnelRow>() {
    public void collect(SeaTunnelRow r) { rows.add(r); }
    public Object getCheckpointLock() { return this; }
    public void close() {}
});
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure the call site uses the Collector overload
if (collector == null) throw new IllegalArgumentException("Must call deserialize(byte[], Collector<SeaTunnelRow>)");

Try / catch

try {
    deserializer.deserialize(message, collector);
} catch (UnsupportedOperationException e) {
    // wrong overload used; switch call site to collector-based API
}

Prevention

When it happens

Trigger: Calling deserializer.deserialize(messageBytes) directly (the single-argument overload) instead of deserialize(messageBytes, collector) — in custom code, test harnesses, or engine adapters written against the old single-row API.

Common situations: Unit tests exercising the Debezium JSON format with the wrong overload; a custom SourceReader collecting rows without a Collector; connector code written before the collector-based API became standard.

Related errors


AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10). Data as JSON: /api/errors/8dff9388cf1576c7. Report an issue: GitHub.