apache/seatunnel · error · SeaTunnelEngineException

Unsupported row type

Error message

Unsupported row type: ${rowType.getClass().getName()}

What it means

SeaTunnelSourceCollector.collect computes a row's byte size using its row type. It supports SeaTunnelRowType (single table) and MultipleRowType (multi-table via a per-table type map); any other SeaTunnelRowType implementation reaches the else branch and throws SeaTunnelEngineException with the class name. This guards the flow-control/metrics path against unknown row-type wrappers.

Solutions

  1. Upgrade/align the connector jar and engine versions so both use the same SeaTunnelRowType classes
  2. Make the source emit standard SeaTunnelRowType (or MultipleRowType for multi-table sources)
  3. Add a branch in SeaTunnelSourceCollector for the new row type if it is legitimately supported
  4. Check the reported class name to identify which connector/version produced the unsupported type

Example fix

// before (custom source)
return new MyCustomRowType(...); // unsupported by collector
// after
return new SeaTunnelRowType(new String[]{"id"}, new SeaTunnelDataType[]{BasicType.LONG_TYPE});
Defensive patterns

Strategy: try-catch

Validate before calling

if (!(rowType instanceof SeaTunnelRowType) && !(rowType instanceof MultipleRowType)) throw new IllegalArgumentException("Unsupported row type: " + rowType.getClass().getName());

Type guard

boolean isSupportedRowType(SeaTunnelRowType t) { return t instanceof SeaTunnelRowType || t instanceof MultipleRowType; }

Try / catch

try { collector.collect(row); } catch (SeaTunnelEngineException e) { log.error("Row type {} unsupported by engine; align connector jar with engine version", e.getMessage()); failTask(e); }

Prevention

When it happens

Trigger: A source emits rows whose RowType container is neither SeaTunnelRowType nor MultipleRowType — typically a custom catalog table type or a newer/older SeaTunnelRowType variant crossing engine versions.

Common situations: Custom source connectors returning bespoke row types; mixed seatunnel-api versions between a connector fat jar and the Zeta engine; schema-change scenarios (multi-table) where the collector's type map is populated only for MultipleRowType.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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

Appendix: source

Thrown at seatunnel-engine/seatunnel-engine-server/src/main/java/org/apache/seatunnel/engine/server/task/SeaTunnelSourceCollector.java:304

    /** Updates source-side metrics, samples new traces when enabled, and forwards the record. */
    @Override
    public void collect(T row) {
        if (dryRunSampleEnabled && dryRunSampleCount >= dryRunSampleLimit) {
            return;
        }
        try {
            if (row instanceof SeaTunnelRow) {
                String tableId = ((SeaTunnelRow) row).getTableId();
                // init the size of row early with rowType, this way is faster than init the size
                // without rowType
                int size;
                if (rowType instanceof SeaTunnelRowType) {
                    size = ((SeaTunnelRow) row).getBytesSize((SeaTunnelRowType) rowType);
                } else if (rowType instanceof MultipleRowType) {
                    size = ((SeaTunnelRow) row).getBytesSize(rowTypeMap.get(tableId));
                } else {
                    throw new SeaTunnelEngineException(
                            "Unsupported row type: " + rowType.getClass().getName());
                }
                flowControlGate.audit((SeaTunnelRow) row);
                connectorMetricsCalcContext.updateMetrics(row, tableId);
                tryStainTrace((SeaTunnelRow) row);
            }
            if (dryRunSamplePrintData) {
                dryRunSampleCount++;
                log.info("Dry-run sample [source] row {}: {}", dryRunSampleCount, row);
            } else if (dryRunSampleEnabled) {
                dryRunSampleCount++;
            }
            sendRecordToNext(new Record<>(row));
            emptyThisPollNext = false;
            if (dryRunSampleEnabled) {
                if (dryRunSampleCount == dryRunSampleLimit && dryRunSampleComplete != null) {
                    dryRunSampleComplete.run();
                }

View on GitHub (pinned to cf67b549a7)