apache/kafka · error · IllegalStateException
MockProducer has already been initialized for transactions.
Error message
MockProducer has already been initialized for transactions.
What it means
Thrown by MockProducer.initTransactions(boolean) when transactionInitialized is already true. MockProducer (used in unit tests for exactly-once/transactional code) models transactional state explicitly; initTransactions may only be called once per instance to mirror the real producer's contract that transaction initialization is a one-shot setup.
Source
Thrown at clients/src/main/java/org/apache/kafka/clients/producer/MockProducer.java:160
final Serializer<V> valueSerializer) {
this(Cluster.empty(), autoComplete, partitioner, keySerializer, valueSerializer);
}
/**
* Create a new mock producer with invented metadata.
*
* Equivalent to {@link #MockProducer(Cluster, boolean, Partitioner, Serializer, Serializer) new MockProducer(Cluster.empty(), false, null, null, null)}
*/
public MockProducer() {
this(Cluster.empty(), false, null, null, null);
}
@Override
public void initTransactions(boolean keepPreparedTxn) {
verifyNotClosed();
verifyNotFenced();
if (this.transactionInitialized) {
throw new IllegalStateException("MockProducer has already been initialized for transactions.");
}
if (this.initTransactionException != null) {
throw this.initTransactionException;
}
this.transactionInitialized = true;
this.transactionInFlight = false;
this.transactionCommitted = false;
this.transactionAborted = false;
this.sentOffsets = false;
}
@Override
public void beginTransaction() throws ProducerFencedException {
verifyNotClosed();
verifyNotFenced();
verifyTransactionsInitialized();
if (this.beginTransactionException != null) {View on GitHub (pinned to c31c9215e1)
Solutions
- Create a fresh MockProducer for each test (in @BeforeEach) rather than re-initializing.
- Move initTransactions() out of test code if the test base already calls it.
- Guard with a flag or use @BeforeEach to reset state by constructing a new instance.
- If you genuinely need to re-init, discard the old MockProducer and construct a new one.
Example fix
// before
private final MockProducer<String,String> mp = new MockProducer<>();
@BeforeEach void setup() { mp.initTransactions(); }
@Test void myTest() { mp.initTransactions(); /* throws */ }
// after
private MockProducer<String,String> mp;
@BeforeEach void setup() {
mp = new MockProducer<>(); // fresh per test
mp.initTransactions(); // called exactly once per instance
} Defensive patterns
Strategy: validation
Validate before calling
// MockProducer.initTransactions(keepPreparedTxn) throws IllegalStateException
// if already initialized. In tests, call it exactly once per MockProducer
// instance and track it.
MockProducer mp = new MockProducer(Cluster.empty(), false, null, null, null);
// track init in the test, or wrap:
java.util.concurrent.atomic.AtomicBoolean inited = new java.util.concurrent.atomic.AtomicBoolean();
void initOnce(MockProducer m, boolean keepPrepared) {
if (!inited.compareAndSet(false, true)) {
throw new IllegalStateException("initTransactions already called on this mock");
}
m.initTransactions(keepPrepared);
} Try / catch
try {
mockProducer.initTransactions();
} catch (IllegalStateException e) {
if (e.getMessage().contains("already been initialized")) {
// expected if the @BeforeEach already initialized; ignore in tests
return;
}
throw e;
} Prevention
- Create a fresh MockProducer per test method (e.g. in @BeforeEach) so init state never leaks across tests.
- Call initTransactions() exactly once per mock; centralize it in test setup.
- Do not reuse a static MockProducer across tests; its transaction flags persist.
- Assert the expected transaction sequence in tests with the mock's history methods.
When it happens
Trigger: Calling mockProducer.initTransactions() or initTransactions(true) a second time on the same MockProducer instance.
Common situations: JUnit @BeforeEach that builds and inits a shared producer plus test code that also calls initTransactions; a test base class and a subclass both initializing; reusing a MockProducer field across parameterized test invocations without recreating it.
Related errors
- Transaction already started
- Invalid producer ID and epoch values: {producerId}:{epoch}.
- Invalid serialized transaction state format: {serializedStat
- Must set retries to non-zero when using the idempotent produ
- Cannot set a transactional.id without also enabling idempote
AI-assisted analysis of apache/kafka@c31c9215e1 (2026-08-03).
Data as JSON: /data/errors/1c49e7b871001bc3.json.
Report an issue: GitHub.