apache/seatunnel · warning
Multi-table sink encountered non-row-level error in plugin
Error message
Multi-table sink encountered non-row-level error in plugin [{}], table [{}]: {} What it means
EngineMultiTableRowErrorHandler.handleRowError classifies sink exceptions as row-level (skippable) or system-level (fatal). When isRowError() returns false, this warning is logged with plugin and table context and the handler returns false, telling the caller to treat the error as fatal. It means a write failure occurred that the error-handling policy does not consider safe to skip per-row.
Solutions
- Read the chained cause: fix the underlying system-level issue (connectivity, permissions, schema) and rerun.
- If the exception is genuinely row-scoped but misclassified, upgrade/patch the connector's exception classification.
- Adjust job design so system-level failures are retried rather than skipped — do not force these to be skippable.
- If too many such warnings appear, check whether the error-handling config (row vs system errors) matches the connector's behavior.
Example fix
null
Defensive patterns
Strategy: try-catch
Validate before calling
null
Type guard
null
Try / catch
boolean handled = rowErrorHandler.handleRowError(writer, tableId, row, t);
if (!handled) {
// system-level failure: rethrow as fatal
throw new RuntimeException("Non-row-level sink error in " + tableId, t);
} Prevention
- Monitor error-sink/target DB availability
- Classify connector exceptions correctly so row-scoped failures are not treated as system-level
- Set up retry for system-level errors instead of expecting them to be skipped
When it happens
Trigger: A multi-table sink write throws an exception not classified as a row error (e.g. connection loss, serialization failure of the whole batch, null writer, generic RuntimeException/SQLException not in the row-error categories), with row error handling enabled.
Common situations: Error-sink/target database outage during a run; batch-level failures where individual rows cannot be identified; misconfigured error handler expecting all failures to be skippable; connector throwing wrapper exceptions not recognized by isRowError.
Related errors
- Close ErrorHandler for transform stage failed
- Flush ErrorHandler for transform stage failed
- Row-level error in stage
- Unable to create a sink for identifier 'MultiTableSink'.
AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10).
Data as JSON: /api/errors/d5cde2ae5cf7495c.
Report an issue: GitHub.
Appendix: source
Thrown at seatunnel-engine/seatunnel-engine-server/src/main/java/org/apache/seatunnel/engine/server/task/error/EngineMultiTableRowErrorHandler.java:75
RowErrorClassifier<SeaTunnelRow> rowErrorClassifier,
String pluginName,
BiConsumer<SeaTunnelRow, ErrorHandlingSinkWriter.WriteOutcome> outcomeConsumer,
EngineRowErrorCollector rowErrorCollector) {
this.errorHandler = errorHandler;
this.rowErrorClassifier = rowErrorClassifier;
this.pluginName = pluginName;
this.outcomeConsumer = outcomeConsumer;
this.rowErrorCollector = rowErrorCollector;
}
@Override
public boolean handleRowError(
SinkWriter<SeaTunnelRow, ?, ?> writer, String tableId, SeaTunnelRow row, Throwable t) {
String effectiveTableId = tableId != null ? tableId : resolveTableId(row);
if (!isRowError(writer, row, t)) {
// System-level error: let caller treat it as fatal.
log.warn(
"Multi-table sink encountered non-row-level error in plugin [{}], table [{}]: {}",
pluginName,
effectiveTableId,
t != null ? t.getMessage() : null,
t);
return false;
}
RowErrorContext ctx = new RowErrorContext("SINK", "SINK", pluginName, effectiveTableId);
// Delegate to shared ErrorHandler; it may throw when thresholds or queue policies demand
// a job failure.
log.debug(
"Routing multi-table row-level error to error handler for plugin [{}], table [{}]: {}",
pluginName,
effectiveTableId,
t != null ? t.getMessage() : null);
ErrorHandler.ErrorHandleResult result = errorHandler.onError(ctx, row, t);View on GitHub (pinned to cf67b549a7)