apache/seatunnel · warning

Field is null, setting to NULL in prepared statement

Error message

Field {} is null, setting to NULL in prepared statement

What it means

In DatabendSinkWriter.processRow(), each field of the row is bound to the PreparedStatement. When a field is null, the writer logs this warning and binds SQL NULL via setNull(i+1, Types.VARCHAR). This is informational: the write continues with a NULL in that column. Note it uses VARCHAR regardless of the column's real type, and will fail if the target column is NOT NULL.

Solutions

  1. If the column is NOT NULL in Databend, populate the field upstream or set a default value before the sink
  2. Filter or coalesce null fields with a transform (e.g. CASE/COALESCE in SQL transform)
  3. Verify field ordering matches the target table column order — nulls in the wrong position indicate mapping misalignment
  4. If large volumes of this warning appear, disable per-field INFO/WARN logging in processRow — it is very hot-path heavy and slows throughput

Example fix

// before
if (field == null) {
    log.warn("Field {} is null, setting to NULL in prepared statement", i + 1);
    preparedStatement.setNull(i + 1, java.sql.Types.VARCHAR);
}
// after
if (field == null) {
    preparedStatement.setNull(i + 1, columnSqlTypes[i]); // correct JDBC type per column
}
Defensive patterns

Strategy: validation

Validate before calling

// pre-validate nulls against target NOT NULL columns
for (int i = 0; i < row.getFields().length; i++) {
    if (row.getFields()[i] == null && notNullColumns.contains(i)) {
        throw new IllegalArgumentException("Field " + i + " is NULL but column is NOT NULL");
    }
}

Type guard

boolean hasNulls(SeaTunnelRow row) {
    for (Object f : row.getFields()) { if (f == null) return true; }
    return false;
}

Try / catch

try {
    writer.write(row);
} catch (SQLException e) {
    if (e.getMessage() != null && e.getMessage().toLowerCase().contains("null")) {
        log.error("NOT NULL constraint violated; null field bound to non-nullable column", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Any row containing a null field is processed in the traditional insert path (write -> processTraditionalRow -> processRow).

Common situations: Sparse/optional columns in source data; outer joins producing nulls; missing values in CSV/JSON sources; mapping mistakes leaving fields unpopulated. Fails with NOT NULL violation when the Databend column disallows NULL.

Related errors


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

Appendix: source

Thrown at seatunnel-connectors-v2/connector-databend/src/main/java/org/apache/seatunnel/connectors/seatunnel/databend/sink/DatabendSinkWriter.java:672

                fieldTypes[i] = BasicType.DOUBLE_TYPE;
            } else if (field instanceof Float) {
                fieldTypes[i] = BasicType.FLOAT_TYPE;
            } else if (field instanceof Boolean) {
                fieldTypes[i] = BasicType.BOOLEAN_TYPE;
            } else {
                fieldTypes[i] = BasicType.STRING_TYPE;
            }
        }

        return new SeaTunnelRowType(fieldNames, fieldTypes);
    }

    private void processRow(SeaTunnelRow row) throws SQLException {
        log.info("Processing row with {} fields", row.getFields().length);
        for (int i = 0; i < row.getFields().length; i++) {
            Object field = row.getFields()[i];
            if (field == null) {
                log.warn("Field {} is null, setting to NULL in prepared statement", i + 1);
                preparedStatement.setNull(i + 1, java.sql.Types.VARCHAR);
            } else {
                log.info(
                        "Setting parameter {}: {} ({})",
                        i + 1,
                        field,
                        field.getClass().getSimpleName());
                preparedStatement.setObject(i + 1, field);
            }
        }
        preparedStatement.addBatch();
        log.info("Added row to batch, current batch count: {}", batchCount + 1);
    }

    private void verifyRawTableData(String rawTableName, String database) throws SQLException {
        try (Statement stmt = connection.createStatement();
                ResultSet rs =
                        stmt.executeQuery(

View on GitHub (pinned to cf67b549a7)