aeron-io/aeron · error · AeronException
unexpected close of heartbeat timestamp counter
Error message
unexpected close of heartbeat timestamp counter: <counterId>
What it means
AeronException thrown when the client attempts to update its heartbeat timestamp counter but the underlying counter has been closed (freed by the driver timing the client out). This is a race between driver-side client timeout and client-side keepalive; the conductor terminates since the driver no longer considers this client live.
Solutions
- Treat the client as terminated and create a new Aeron instance (this is by design after driver eviction)
- Keep the conductor serviced promptly: avoid blocking callbacks and long pauses (see interServiceTimeout)
- Increase driver-side and client-side timeouts so marginal pauses do not evict the client
- Inspect getCause() to confirm the counter-free race if diagnostics are needed
Example fix
// before Aeron aeron = Aeron.connect(ctx); // long blocking work on the same thread ... // after Aeron aeron = Aeron.connect(ctx); runBlockingWorkOnSeparateExecutor(); // conductor stays serviced, client not evicted
Defensive patterns
Strategy: fallback
Validate before calling
// Before heavy work that may stall the conductor:
if (System.nanoTime() - lastServiceNs > interServiceTimeoutNs / 2) { serviceConductorNow(); } Try / catch
catch (AeronException e) { if (e.getMessage().startsWith("unexpected close of heartbeat timestamp counter")) { client.close(); client = Aeron.connect(ctx); } } // driver evicted this client; reconnect Prevention
- Keep the conductor thread responsive; offload blocking work
- Set driver/client timeouts comfortably above worst-case pauses
- After driver eviction always create a new Aeron client rather than reusing the old one
When it happens
Trigger: The driver timed out this client (e.g. because its conductor thread was starved) and freed the heartbeat counter; the client's next keepalive pass hits the closed counter and wraps the resulting exception.
Common situations: Client thread stalls long enough for the driver to expire the client, then resumes and races keepalive; paused VM/container resuming after driver timeout; debugging sessions freezing the client past the driver timeout.
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
- MediaDriver ( ) keepalive: age= ms > timeout= ms
- Driver events adapter is invalid
- no response from MediaDriver within
- CnC file is created but not initialised
- CnC file not created: <cncFile.getAbsolutePath()>
AI-assisted analysis of aeron-io/aeron@6d60124e15 (2026-09-12).
Data as JSON: /api/errors/9c50ec1f20197cf1.
Report an issue: GitHub.
Appendix: source
Thrown at aeron-client/src/main/java/io/aeron/ClientConductor.java:1923
countersReader, HEARTBEAT_TYPE_ID, ctx.clientId());
if (NULL_COUNTER_ID != counterId)
{
try
{
heartbeatTimestamp = new AtomicCounter(counterValuesBuffer, counterId);
heartbeatTimestamp.setRelease(nowMs);
appendToLabel(
countersReader.metaDataBuffer(),
counterId,
" name=" + ctx.clientName() + " " +
formatVersionInfo(AeronVersion.VERSION, AeronVersion.GIT_SHA));
timeOfLastKeepAliveNs = nowNs;
}
catch (final RuntimeException ex) // a race caused by the driver timing out the client
{
terminateConductor();
throw new AeronException("unexpected close of heartbeat timestamp counter: " + counterId, ex);
}
}
}
else
{
final int counterId = heartbeatTimestamp.id();
if (!HeartbeatTimestamp.isActive(countersReader, counterId, HEARTBEAT_TYPE_ID, ctx.clientId()))
{
terminateConductor();
throw new AeronException("unexpected close of heartbeat timestamp counter: " + counterId);
}
heartbeatTimestamp.setRelease(nowMs);
timeOfLastKeepAliveNs = nowNs;
}
return 1;
}View on GitHub (pinned to 6d60124e15)