aeron-io/aeron · error · AeronException
reentrant calls not permitted during callbacks
Error message
reentrant calls not permitted during callbacks
What it means
ensureNotReentrant() throws this when a client callback (e.g. AvailableImageHandler, UnavailableCounterHandler, ReservedValueSupplier) makes a re-entrant call back into the ClientConductor that would mutate state while the conductor is iterating inside its own callback. Re-entrant mutation during callbacks can corrupt conductor state, so it is forbidden.
Solutions
- Do not call state-changing client APIs from inside callbacks; instead enqueue the action and execute it on another thread
- Use Aeron's async APIs: schedule close/add work outside the callback via an executor
- Use AtomicCounter or queue signals from the callback and act in your own loop
- If teardown is needed, defer with a separate executor thread that performs the close
Example fix
// before subscription.onUnavailableImage(img -> aeron.close()); // reentrant call // after subscription.onUnavailableImage(img -> closeExecutor.execute(() -> aeron.close()));
Defensive patterns
Strategy: try-catch
Try / catch
try { conductorCall(); } catch (AeronException e) { if (e.getMessage().contains("reentrant")) { deferToOtherThread(action); } else { throw e; } } Prevention
- Never call close/add/remove APIs from inside available/unavailable handlers
- Use an executor to defer teardown work out of callbacks
- Keep handlers lightweight: enqueue, don't mutate conductor state
When it happens
Trigger: From within an onAvailableImage/onUnavailableImage/onAvailableCounter callback, calling APIs that require conductor state changes such as Aeron.close(), addSubscription/addPublication removal, or other state-mutating calls on the same client thread.
Common situations: Calling aeron.close() inside an unavailable-image handler; adding/removing subscriptions inside image callbacks; complex teardown logic embedded in listeners running on the conductor thread.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- client is closed
- reentrant calls not permitted during callbacks
- client is closed
- counter id is not allocated, state
- Aeron client is terminating
AI-assisted analysis of aeron-io/aeron@6d60124e15 (2026-09-12).
Data as JSON: /api/errors/c3b52e678e074f1f.
Report an issue: GitHub.
Appendix: source
Thrown at aeron-client/src/main/java/io/aeron/ClientConductor.java:1728
private void ensureActive()
{
if (isClosed)
{
throw new AeronException("Aeron client is closed");
}
if (isTerminating)
{
throw new AeronException("Aeron client is terminating");
}
}
private void ensureNotReentrant()
{
if (isInCallback)
{
throw new AeronException("reentrant calls not permitted during callbacks");
}
}
private LogBuffers logBuffers(final long registrationId, final String logFileName, final String channel)
{
LogBuffers logBuffers = logBuffersByIdMap.get(registrationId);
if (null == logBuffers)
{
try
{
logBuffers = logBuffersFactory.map(logFileName);
if (ctx.preTouchMappedMemory())
{
logBuffers.preTouch();
}
logBuffersByIdMap.put(registrationId, logBuffers);View on GitHub (pinned to 6d60124e15)