aeron-io/aeron · critical · AgentTerminationException
unexpected Aeron close
Error message
unexpected Aeron close
What it means
ArchiveConductor's doWork duty cycle detects that the owning Aeron client was closed (or an abort was requested) while the archive agent was still running. The library throws AgentTerminationException to shut down the archive agent immediately because it can no longer perform any useful work without a live Aeron client. This is a lifecycle violation, not a transient failure.
Solutions
- Ensure shutdown order: stop/close the Archive (archive.close()) before closing the Aeron client it was built with.
- Reuse a single shared Aeron client for the Archive and do not close it while the archive agent is running.
- In shutdown hooks, stop the agent runner driving doWork() first, then call aeron.close().
- If abort was triggered externally, check whether your code calls archive.conductor().abort() or a forced termination path unintentionally.
- Check for close() calls from other threads (multiple services sharing one Aeron instance) and remove the premature close.
Example fix
// before aeron.close(); archive.close(); // after archive.close(); aeron.close();
Defensive patterns
Strategy: try-catch
Validate before calling
// before relying on archive
if (aeron.isClosed()) {
throw new IllegalStateException("Aeron client closed; do not start Archive");
} Try / catch
try {
archive = Archive.launch(ctx.client(aeron));
} catch (AgentTerminationException e) {
log.error("Aeron client closed while archive running", e);
// orderly shutdown: close archive then client
} Prevention
- Always close Archive before the shared Aeron client.
- Use try-with-resources with archive declared before aeron.
- Do not share one Aeron client across independently-lifecycled services.
- Centralize shutdown in one component to enforce ordering.
When it happens
Trigger: Aeron.close() (or the context close) is called on the Aeron client used by the Archive while ArchiveConductor.doWork() is still being driven; or abort() is invoked on the conductor (e.g. during shutdown with a closed conductor).
Common situations: Application shuts down the Aeron client before stopping the Archive service; ordering mistake in a shutdown hook; using Aeron.connect() with an Archive that outlives the client; abrupt process shutdown racing the agent duty cycle.
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
- unexpected driver close
- response publication is closed: " + session
- recording events publication is closed
- ConcurrentConcludeException
- client is closed
AI-assisted analysis of aeron-io/aeron@6d60124e15 (2026-09-12).
Data as JSON: /api/errors/f4b2d5c6f96e939d.
Report an issue: GitHub.
Appendix: source
Thrown at aeron-archive/src/main/java/io/aeron/archive/ArchiveConductor.java:371
}
catch (final InterruptedException ignore)
{
Thread.currentThread().interrupt();
}
}
/**
* {@inheritDoc}
*/
@Override
public int doWork()
{
final long nowNs = nanoClock.nanoTime();
int workCount = 0;
if (isAbort)
{
throw new AgentTerminationException("unexpected Aeron close");
}
dutyCycleTracker.measureAndUpdate(nowNs);
final long nowMs = epochClock.time();
if (cachedEpochClock.time() != nowMs)
{
cachedEpochClock.update(nowMs);
workCount += invokeAeronInvoker();
if (nowMs >= markFileUpdateDeadlineMs)
{
markFileUpdateDeadlineMs = nowMs + MARK_FILE_UPDATE_INTERVAL_MS;
markFile.updateActivityTimestamp(nowMs);
}
}
workCount += controlSessionAdapter.poll();View on GitHub (pinned to 6d60124e15)