apache/seatunnel · error · KafkaConnectorException

ILLEGAL_ARGUMENT

ILLEGAL_ARGUMENT

Error message

Field '%s' cannot be in both partition_key_fields and kafka_headers_fields

What it means

getSerializer() validates that no field appears in both partition_key_fields and kafka_headers_fields; a field used as the partition key cannot also be written as a message header. Throws ILLEGAL_ARGUMENT naming the offending field.

Solutions

  1. Remove the overlapping field from one of the two lists
  2. If the value is needed in both places, use a duplicate/copy column for the header and keep the original as the partition key

Example fix

// before
partition_key_fields = ["tenant_id"]
kafka_headers_fields = ["tenant_id", "trace_id"]
// after
partition_key_fields = ["tenant_id"]
kafka_headers_fields = ["trace_id"]
Defensive patterns

Strategy: validation

Validate before calling

Set<String> overlap = new HashSet<>(partitionKeyFields);
overlap.retainAll(headerFields);
if (!overlap.isEmpty()) {
  throw new IllegalArgumentException("Fields in both partition_key_fields and kafka_headers_fields: " + overlap);
}

Prevention

When it happens

Trigger: A column name is listed in both partition_key_fields and kafka_headers_fields lists; detected at writer initialization while building the serializer.

Common situations: User keys the partition by the same column they also mirror into Kafka headers (e.g. tenant_id), assuming overlap is allowed.

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


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

Appendix: source

Thrown at seatunnel-connectors-v2/connector-kafka/src/main/java/org/apache/seatunnel/connectors/seatunnel/kafka/sink/KafkaSinkWriter.java:213

        String delimiter = DEFAULT_FIELD_DELIMITER;

        if (pluginConfig.get(FIELD_DELIMITER) != null) {
            delimiter = pluginConfig.get(FIELD_DELIMITER);
        }
        if (pluginConfig.get(PARTITION_KEY_FIELDS) != null && pluginConfig.get(PARTITION) != null) {
            throw new KafkaConnectorException(
                    KafkaConnectorErrorCode.GET_TRANSACTIONMANAGER_FAILED,
                    "Cannot select both `partiton` and `partition_key_fields`. You can configure only one of them");
        }

        // Validate that partition_key_fields and kafka_headers_fields don't overlap
        List<String> partitionKeyFields = getPartitionKeyFields(pluginConfig, seaTunnelRowType);
        List<String> headerFields = getHeaderFields(pluginConfig, seaTunnelRowType);
        if (!partitionKeyFields.isEmpty() && !headerFields.isEmpty()) {
            for (String headerField : headerFields) {
                if (partitionKeyFields.contains(headerField)) {
                    throw new KafkaConnectorException(
                            CommonErrorCode.ILLEGAL_ARGUMENT,
                            String.format(
                                    "Field '%s' cannot be in both partition_key_fields and kafka_headers_fields",
                                    headerField));
                }
            }
        }

        if (pluginConfig.get(PARTITION_KEY_FIELDS) != null) {
            return DefaultSeaTunnelRowSerializer.create(
                    topic,
                    partitionKeyFields,
                    headerFields,
                    seaTunnelRowType,
                    messageFormat,
                    delimiter,
                    pluginConfig);
        }

View on GitHub (pinned to cf67b549a7)