apache/seatunnel · error · IotdbConnectorException
ILLEGAL_ARGUMENT
ILLEGAL_ARGUMENT
Error message
Illegal SeaTunnelRowType:
What it means
DefaultSeaTunnelRowDeserializer.convert() for table-format records expects the IoTDB RowRecord field count to equal rowType.getTotalFields() - 1 (the timestamp becomes the first SeaTunnel column). A mismatch throws ILLEGAL_ARGUMENT with the offending record.
Source
Thrown at seatunnel-connectors-v2/connector-iotdb-v2/src/main/java/org/apache/seatunnel/connectors/seatunnel/iotdbv2/serialize/DefaultSeaTunnelRowDeserializer.java:57
public class DefaultSeaTunnelRowDeserializer implements SeaTunnelRowDeserializer {
private final SeaTunnelRowType rowType;
private final String sqlDialect;
@Override
public SeaTunnelRow deserialize(RowRecord rowRecord) {
if (SourceConstants.TABLE.equalsIgnoreCase(sqlDialect)) {
return convertTableRow(rowRecord);
}
return convert(rowRecord);
}
private SeaTunnelRow convert(RowRecord rowRecord) {
long timestamp = rowRecord.getTimestamp();
List<Field> fields = rowRecord.getFields();
if (fields.size() != (rowType.getTotalFields() - 1)) {
throw new IotdbConnectorException(
CommonErrorCode.ILLEGAL_ARGUMENT, "Illegal SeaTunnelRowType: " + rowRecord);
}
Object[] seaTunnelFields = new Object[rowType.getTotalFields()];
seaTunnelFields[0] = convertTimestamp(timestamp, rowType.getFieldType(0));
for (int i = 1; i < rowType.getTotalFields(); i++) {
Field field = fields.get(i - 1);
if (field == null || field.getDataType() == null) {
seaTunnelFields[i] = null;
continue;
}
SeaTunnelDataType<?> seaTunnelFieldType = rowType.getFieldType(i);
seaTunnelFields[i] = convert(seaTunnelFieldType, field);
}
return new SeaTunnelRow(seaTunnelFields);
}
private SeaTunnelRow convertTableRow(RowRecord rowRecord) {
List<Field> fields = rowRecord.getFields();View on GitHub (pinned to cf67b549a7)
Solutions
- Align the SeaTunnel catalog schema so totalFields == IoTDB fields + 1 (timestamp first).
- Re-check the IoTDB query's selected measurements; ensure all are present in each record.
- Update the job config after any IoTDB timeseries schema change.
Example fix
// before rowType fields = [ts, temp] // IoTDB returns 2 fields // after rowType fields = [ts, temp, humidity] // matches IoTDB's 2 fields + timestamp
Defensive patterns
Strategy: validation
Validate before calling
// before deserialization
if (iotdbRecord.getFields().size() + 1 != rowType.getTotalFields()) {
throw new IllegalStateException("Schema mismatch: IoTDB fields=" + iotdbRecord.getFields().size()
+ " expected=" + (rowType.getTotalFields() - 1));
} Try / catch
try {
SeaTunnelRow row = deserializer.deserialize(record);
} catch (IotdbConnectorException e) {
log.error("Record does not match declared schema: {}", e.getMessage());
throw e;
} Prevention
- Keep SeaTunnel schema = IoTDB measurements + leading timestamp column.
- Re-sync schema whenever IoTDB timeseries change.
- Query measurements explicitly, not with wildcards.
When it happens
Trigger: Deserializing an IoTDB RowRecord whose field count differs from the SeaTunnelRowType total minus one, e.g., the IoTDB measurement set changed or the declared schema has wrong column count.
Common situations: Measurements added/removed in IoTDB after the SeaTunnel job was configured, schema mismatch between source table definition and IoTDB timeseries, or selected measurements filtered out by the query.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10).
Data as JSON: /api/errors/cbd7051897a05bb9.
Report an issue: GitHub.