apache/seatunnel · error · UnsupportedOperationException

Please invoke DeserializationSchema#deserialize(byte[], Coll

Error message

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

What it means

Like the base DebeziumJsonDeserializationSchema, the Dispatcher variant can expand one message into multiple rows (UPDATE_BEFORE + UPDATE_AFTER), so only the collector-based deserialize(byte[], Collector<SeaTunnelRow>) is implemented. The single-row overload deserialize(byte[]) throws UnsupportedOperationException unconditionally.

Source

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

    private static final String SOURCE = "source";
    private static final String TABLE = "table";
    private static final String SCHEMA = "schema";
    private static final String DATABASE = "db";
    private static final String CONNECTOR = "connector";

    public DebeziumJsonDeserializationSchemaDispatcher(
            Map<TablePath, DebeziumJsonDeserializationSchema> tableDeserializationMap,
            boolean ignoreParseErrors,
            boolean debeziumEnabledSchema) {
        this.tableDeserializationMap = tableDeserializationMap;
        this.debeziumEnabledSchema = debeziumEnabledSchema;
        this.ignoreParseErrors = ignoreParseErrors;
    }

    @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) {
        if (message == null || message.length == 0) {
            // skip tombstone messages
            return;
        }

        try {
            JsonNode payload = getPayload(JsonUtils.readTree(message));
            JsonNode source = payload.get(SOURCE);
            String database = getNodeValue(source, DATABASE);
            String schema = getNodeValue(source, SCHEMA);
            String table = getNodeValue(source, TABLE);
            TablePath tablePath = TablePath.of(database, schema, table);
            if (tableDeserializationMap.containsKey(tablePath)) {

View on GitHub (pinned to cf67b549a7)

Solutions

  1. Switch to deserialize(byte[] message, Collector<SeaTunnelRow> out)
  2. Wrap a buffering Collector if you need rows returned as a list
  3. Update test harnesses to the collector-based API

Example fix

// before
SeaTunnelRow row = dispatcher.deserialize(message);
// after
List<SeaTunnelRow> rows = new ArrayList<>();
dispatcher.deserialize(message, row -> rows.add(row)); // adapt to full Collector interface
Defensive patterns

Strategy: try-catch

Validate before calling

if (!(deserializer instanceof DebeziumJsonDeserializationSchemaDispatcher)) return;
// always invoke the Collector overload for CDC formats

Try / catch

try {
    dispatcher.deserialize(message, collector);
} catch (UnsupportedOperationException e) {
    log.error("Use deserialize(byte[], Collector<SeaTunnelRow>) for Debezium dispatchers", e);
    throw e;
}

Prevention

When it happens

Trigger: Calling debeziumEnabledSchema.deserialize(messageBytes) (single-argument overload) instead of deserialize(messageBytes, out) on DebeziumJsonDeserializationSchemaDispatcher.

Common situations: Test code and utilities written against the older single-row API; custom engine adapters or SourceReaders that bypass the Collector contract; copy-pasted deserialization snippets from other formats.

Related errors


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