apache/seatunnel · warning

Suppressed an additional asynchronous send failure of Kafka…

Error message

Suppressed an additional asynchronous send failure of Kafka transaction [{}]

What it means

Kafka's producer callback for an ongoing transaction reported an exception after a previous send failure was already captured. Only the first exception becomes the checkpoint failure cause; subsequent ones are logged and suppressed to avoid masking the primary error.

Solutions

  1. Inspect this suppressed log for additional affected partitions and root causes
  2. Check the first asyncSendException / checkpoint failure exception, which is the primary cause
  3. Verify broker health, replication, and that the transactional producer can reach the cluster
  4. Review ACLs (IDEVENT/WRITE) for the transactional producer user
Defensive patterns

Strategy: try-catch

Validate before calling

// Check transactional producer health before/at checkpoint time
producer.partitionsFor(topic); // fails fast on broker/ACL issues

Try / catch

// In callback: retain first failure, log the rest
AtomicReference<Exception> first = new AtomicReference<>();
callback -> {
    if (e != null && !first.compareAndSet(null, e)) {
        LOG.warn("Suppressed additional send failure", e);
    }
}

Prevention

When it happens

Trigger: onSendCompleted (producer callback) receives a non-null exception while asyncSendException is already set — e.g. multiple partitions' sends fail during the same broker outage, and only the first failure is retained.

Common situations: Broker outage or leader election affecting several partitions at once; transactional.id timeouts; authorization failures on produce after an earlier failure; network partition during transaction commit window.

Related errors


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

Appendix: source

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

        checkAsyncSendException();
        kafkaProducer.send(producerRecord, this::onSendCompleted);
        recordNumInTransaction++;
    }

    /**
     * Records the first asynchronous send failure of the current transaction so that {@link
     * #prepareCommit()} can fail the checkpoint instead of committing a partial transaction.
     *
     * <p>Invoked on the producer's sender thread.
     */
    private void onSendCompleted(RecordMetadata metadata, Exception exception) {
        if (exception == null) {
            return;
        }
        if (!asyncSendException.compareAndSet(null, exception)) {
            // Only the first failure becomes the checkpoint failure cause. Log the later ones so a
            // broker-side incident affecting several partitions can still be diagnosed.
            log.warn(
                    "Suppressed an additional asynchronous send failure of Kafka transaction [{}]",
                    transactionId,
                    exception);
        }
    }

    @Override
    public void beginTransaction(String transactionId) {
        this.transactionId = transactionId;
        this.kafkaProducer = getTransactionProducer(transactionId);
        kafkaProducer.beginTransaction();
        // Reset the per-transaction state. A new transaction always runs on a newly created
        // producer, so a failure recorded for the previous transaction no longer applies. Keeping
        // it would turn a single transient send error into a permanent checkpoint failure loop.
        recordNumInTransaction = 0;
        asyncSendException.set(null);
    }

View on GitHub (pinned to cf67b549a7)