apache/kafka · critical · ProducerFencedException
MockProducer is fenced.
Error message
MockProducer is fenced.
What it means
Thrown by MockProducer.verifyNotFenced() as a ProducerFencedException once the producer has been marked fenced. Fencing is simulated by calling fenceProducer() (line 491), which flips the internal `producerFenced` flag; every transactional operation subsequently calls verifyNotFenced() and aborts. This emulates the broker fencing a producer (epoch bump / duplicate transactional.id) so that transactional code paths can be unit-tested for their fencing handling.
Source
Thrown at clients/src/main/java/org/apache/kafka/clients/producer/MockProducer.java:300
// This should match what's returned in prepareTransaction()
PreparedTxnState currentState = new PreparedTxnState(1000L, (short) 1);
if (currentState.equals(preparedTxnState)) {
commitTransaction();
} else {
abortTransaction();
}
}
private synchronized void verifyNotClosed() {
if (this.closed) {
throw new IllegalStateException("MockProducer is already closed.");
}
}
private synchronized void verifyNotFenced() {
if (this.producerFenced) {
throw new ProducerFencedException("MockProducer is fenced.");
}
}
private void verifyTransactionsInitialized() {
if (!this.transactionInitialized) {
throw new IllegalStateException("MockProducer hasn't been initialized for transactions.");
}
}
private void verifyTransactionInFlight() {
if (!this.transactionInFlight) {
throw new IllegalStateException("There is no open transaction.");
}
}
/**
* Adds the record to the list of sent records. The {@link RecordMetadata} returned will be immediately satisfied.
*View on GitHub (pinned to c31c9215e1)
Solutions
- Confirm fencing was intended — if the test is checking fencing semantics, wrap the next call in try/catch(ProducerFencedException) and call producer.close() as production code should.
- If fencing was set up but the test wants to continue work, create a new MockProducer instance rather than reusing the fenced one (a fenced producer cannot be unfenced, matching real Kafka semantics).
- Move the fenceProducer() call to the exact point in the test where fencing should take effect, not in shared setup, so unrelated assertions don't trip the guard.
- If you call fenceProducer() programmatically, ensure initTransactions() ran first — fenceProducer() itself calls verifyTransactionsInitialized().
Example fix
// before
producer.fenceProducer();
producer.beginTransaction(); // ProducerFencedException
// after
producer.fenceProducer();
try {
producer.beginTransaction();
fail("expected fence");
} catch (ProducerFencedException expected) {
producer.close(Duration.ZERO);
} Defensive patterns
Strategy: try-catch
Try / catch
try {
producer.completeTransaction(prepared);
} catch (ProducerFencedException e) {
// This producer instance has lost its epoch; it must be retired.
// Close it (swallowing further errors) and build a fresh producer.
try { producer.close(Duration.ZERO); } catch (RuntimeException ignore) {}
producer = buildNewProducer();
} Prevention
- Treat ProducerFencedException as terminal for the instance — never retry on the same producer.
- Ensure only one producer per transactional.id is active; a stale instance with the old epoch is what fences the new one.
- On fencing, do a clean handoff: close, then re-init (initTransactions) on the replacement.
- In tests that simulate fencing, assert that application code recreates the producer rather than continuing.
When it happens
Trigger: Calling initTransactions, beginTransaction, sendOffsetsToTransaction, prepareTransaction, commitTransaction, abortTransaction, completeTransaction, or fenceProducer() after fenceProducer() has been invoked on the same MockProducer instance. The throw site is line 300 inside verifyNotFenced().
Common situations: Tests simulating a zombie/fenced producer scenario to verify the application calls producer.close() and exits the transaction loop; a test helper that fences the producer in @BeforeEach being inherited by tests that then continue transactional work; forgetting that fenceProducer() itself requires transactions to be initialized.
Related errors
- MockProducer is already closed.
- MockProducer hasn't been initialized for transactions.
- There is no open transaction.
- clientInstanceId not set
- Producer with transactionalId '{transactionalId}' and {produ
AI-assisted analysis of apache/kafka@c31c9215e1 (2026-08-03).
Data as JSON: /data/errors/89c19ea5f54bdc58.json.
Report an issue: GitHub.