apache/seatunnel · error · UnsupportedOperationException

Please invoke DeserializationSchema#deserialize(byte[], Coll

Error message

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

What it means

CanalJsonDeserializationSchema.deserialize(byte[]) is intentionally unimplemented because a single Canal JSON message may expand into multiple SeaTunnelRow records (batched row data, multiple ops). Only the collector-based deserialize(byte[], Collector<SeaTunnelRow>) is valid, so the direct variant throws UnsupportedOperationException to enforce correct usage.

Source

Thrown at seatunnel-formats/seatunnel-format-json/src/main/java/org/apache/seatunnel/format/json/canal/CanalJsonDeserializationSchema.java:118

            String database,
            String table,
            boolean ignoreParseErrors) {
        this.catalogTable = catalogTable;
        this.seaTunnelRowType = catalogTable.getSeaTunnelRowType();
        this.jsonDeserializer =
                new JsonDeserializationSchema(catalogTable, false, ignoreParseErrors);
        this.database = database;
        this.table = table;
        this.fieldNames = seaTunnelRowType.getFieldNames();
        this.fieldCount = seaTunnelRowType.getTotalFields();
        this.ignoreParseErrors = ignoreParseErrors;
        this.databasePattern = database == null ? null : Pattern.compile(database);
        this.tablePattern = table == null ? null : Pattern.compile(table);
    }

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

    @Override
    public SeaTunnelDataType<SeaTunnelRow> getProducedType() {
        return this.seaTunnelRowType;
    }

    public void deserialize(ObjectNode jsonNode, Collector<SeaTunnelRow> out) throws IOException {
        TablePath tablePath =
                Optional.ofNullable(catalogTable).map(CatalogTable::getTablePath).orElse(null);

        try {
            if (database != null
                    && !databasePattern.matcher(jsonNode.get(FIELD_DATABASE).asText()).matches()) {
                return;
            }
            if (table != null

View on GitHub (pinned to cf67b549a7)

Solutions

  1. Use the collector API: schema.deserialize(message, out) and read rows from the collector
  2. If you need a single row, wrap the collector call and collect all emitted rows into a list, using the first/each as needed
  3. Switch to a deserialization schema designed for single-row output if single-message semantics are required

Example fix

// before
SeaTunnelRow row = canalJsonSchema.deserialize(message);
// after
List<SeaTunnelRow> rows = new ArrayList<>();
canalJsonSchema.deserialize(message, rows::add);
Defensive patterns

Strategy: type-guard

Validate before calling

// Prefer the collector API; never call deserialize(byte[]) on Canal schema
canalJsonSchema.deserialize(message, rowCollector);

Type guard

// Compile-time: always bind to DeserializationSchema#deserialize(byte[], Collector)
BiConsumer<byte[], Collector<SeaTunnelRow>> consume = canalJsonSchema::deserialize;

Try / catch

try { canalJsonSchema.deserialize(message, out); } catch (UnsupportedOperationException e) { /* wrong API used; switch to collector overload */ }

Prevention

When it happens

Trigger: Calling deserialize(byte[] message) directly on a CanalJsonDeserializationSchema instance, e.g. custom code or a framework path that uses the single-row API instead of the Collector overload.

Common situations: Writing custom consumer code that treats the format like a plain JSON deserialization schema; integrating with a runtime/translation layer that calls the byte[]-only overload; unit tests invoking the single-message API.

Related errors


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