aeron-io/aeron · critical · AgentTerminationException

unexpected Aeron close

Error message

unexpected Aeron close

What it means

The backup agent's slowTick invokes the Aeron client invoker and checks whether the shared Aeron client has been closed. An unexpected close of the underlying Aeron client means the agent cannot make progress, so AgentTerminationException is thrown to terminate the agent deliberately.

Solutions

  1. Ensure no other component closes the shared Aeron client while cluster backup is running; tie ownership/lifecycle to the backup.
  2. Inspect the driver/error logs for the root cause that closed the client (e.g. driver inactive) and fix that first.
  3. Restart the backup process once the Aeron driver is healthy.

Example fix

// before
sharedAeron.close(); // elsewhere in the app while backup runs
// after
// close only after ClusterBackup is stopped: backup.close(); then sharedAeron.close();
Defensive patterns

Strategy: try-catch

Try / catch

AgentRunner runner = AgentRunner.run(...); // catch AgentTerminationException in runner error handler
(new AgentRunner(..., (code, ex) -> { if (ex instanceof AgentTerminationException) { restartBackup(); } }))

Prevention

When it happens

Trigger: Something external closes the Aeron client (or its conductor) while ClusterBackupAgent is running — e.g. another owner calls aeron.close(), an unrecoverable client error closes the conductor, or shutdown hooks close the client.

Common situations: Application code sharing one AeronClient across components closing it while a backup is still running; Aeron client terminating itself after a fatal driver error.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of aeron-io/aeron@6d60124e15 (2026-09-12). Data as JSON: /api/errors/280a1d517701df81. Report an issue: GitHub.

Appendix: source

Thrown at aeron-cluster/src/main/java/io/aeron/cluster/ClusterBackupAgent.java:635

        {
            if (EventCode.ERROR == eventCode || EventCode.AUTHENTICATION_REJECTED == eventCode)
            {
                throw new ClusterException(eventCode + ": " + detail);
            }
            else if (EventCode.REDIRECT == eventCode)
            {
                consensusPublicationGroup.closeAndExcludeCurrent();
                state(RESET_BACKUP, epochClock.time());
            }
        }
    }

    private int slowTick(final long nowMs)
    {
        int workCount = aeronClientInvoker.invoke();
        if (aeron.isClosed())
        {
            throw new AgentTerminationException("unexpected Aeron close");
        }

        if (nowMs >= markFileUpdateDeadlineMs)
        {
            markFileUpdateDeadlineMs = nowMs + MARK_FILE_UPDATE_INTERVAL_MS;
            markFile.updateActivityTimestamp(nowMs);
        }

        workCount += pollBackupArchiveEvents();

        if (NULL_VALUE == correlationId && null != clusterArchive)
        {
            final String errorResponse = clusterArchive.pollForErrorResponse();
            if (null != errorResponse)
            {
                ctx.countedErrorHandler().onError(new ClusterEvent("cluster archive error: " + errorResponse));
                state(RESET_BACKUP, nowMs);
            }

View on GitHub (pinned to 6d60124e15)