apache/seatunnel · error · MilvusConnectorException

FIELD_IS_NULL

FIELD_IS_NULL

Error message

FIELD_IS_NULL

What it means

MilvusSinkConverter.buildMilvusData throws FIELD_IS_NULL when a SeaTunnelRow field is null and the corresponding column does not permit null values. Milvus requires the primary key and partition key to be non-null; other fields are only nullable if declared nullable in the catalog schema or if the 'enable.nullable-field' option is turned on. The error message carries the offending field name.

Solutions

  1. Filter out or default null values upstream before writing to the Milvus sink (e.g. a SQL transform with COALESCE/NVL).
  2. Set the sink option 'enable.nullable-field' = true if the target Milvus collection truly allows null for this field.
  3. Verify the catalog table schema marks the column nullable so allowNullableField passes.
  4. Ensure the primary key and partition key columns are never null in your data.

Example fix

// before (row with null field)
row.setField(2, null); // field 'embedding_desc' is not nullable
// after
row.setField(2, defaultValueIfNull(actualValue)); // or set enable.nullable-field=true
Defensive patterns

Strategy: validation

Validate before calling

// before writing to Milvus sink
for (int i = 0; i < rowType.getFieldNames().length; i++) {
    if (element.getField(i) == null && !nullableFields.contains(rowType.getFieldNames()[i])) {
        throw new IllegalArgumentException("Field " + rowType.getFieldNames()[i] + " must not be null");
    }
}

Try / catch

try { sinkWriter.write(row); } catch (MilvusConnectorException e) { if (MilvusConnectionErrorCode.FIELD_IS_NULL.equals(e.getErrorCode())) { log.warn("Null non-nullable field: {}", e.getMessage()); } else { throw e; } }

Prevention

When it happens

Trigger: Writing a row whose field value is null for a column that is not nullable, is the primary key, or is the partition key, while allowNullableField(column, primaryKey, partitionKeyField, enableNullableField) returns false in buildMilvusData.

Common situations: Upstream source produces nulls (e.g. missing JSON keys, LEFT JOIN misses) that are passed straight into the Milvus sink; writing to a Milvus collection whose primary/partition key column receives null; user forgot to enable the nullable-field option even though the collection schema allows nulls.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at seatunnel-connectors-v2/connector-milvus/src/main/java/org/apache/seatunnel/connectors/seatunnel/milvus/utils/sink/MilvusSinkConverter.java:333

        String partitionKeyField = getPartitionKeyField(catalogTable, config);

        JsonObject data = new JsonObject();
        Gson gson = new Gson();
        for (int i = 0; i < seaTunnelRowType.getFieldNames().length; i++) {
            String fieldName = seaTunnelRowType.getFieldNames()[i];
            Boolean isJson = jsonFields.contains(fieldName);
            if (autoId && isPrimaryKeyField(primaryKey, fieldName)) {
                continue; // if create table open AutoId, then don't need insert data with
                // primaryKey field.
            }

            SeaTunnelDataType<?> fieldType = seaTunnelRowType.getFieldType(i);
            Object value = element.getField(i);
            if (value == null) {
                Column column = catalogTable.getTableSchema().getColumn(fieldName);
                if (!allowNullableField(
                        column, primaryKey, partitionKeyField, enableNullableField)) {
                    throw new MilvusConnectorException(
                            MilvusConnectionErrorCode.FIELD_IS_NULL, fieldName);
                }
                if (dynamicField != null
                        && dynamicField.equals(fieldName)
                        && config.get(ENABLE_DYNAMIC_FIELD)) {
                    continue;
                }
                data.add(fieldName, JsonNull.INSTANCE);
                continue;
            }
            // if the field is dynamic field, then parse the dynamic field
            if (dynamicField != null
                    && dynamicField.equals(fieldName)
                    && config.get(ENABLE_DYNAMIC_FIELD)) {
                JsonObject dynamicData = gson.fromJson(value.toString(), JsonObject.class);
                dynamicData
                        .entrySet()
                        .forEach(

View on GitHub (pinned to cf67b549a7)