aeron-io/aeron · error · ArchiveException

authenticator cannot be null

Error message

authenticator cannot be null

What it means

ArchiveConductor obtains the Authenticator by calling ctx.authenticatorSupplier().get() at startup. The archive requires a real authenticator even if no authentication is needed (use a no-op one), so a null result is rejected with ArchiveException. This guards against suppliers that return null by default.

Solutions

  1. Fix the authenticatorSupplier to return a non-null Authenticator instance.
  2. If authentication is not required, supply a permissive no-op Authenticator (e.g. a singleton that always authorises).
  3. Use Archive.Configuration.authenticatorSupplier() default, which returns a valid no-op authenticator.

Example fix

// before
ctx.authenticatorSupplier(() -> null);
// after
ctx.authenticatorSupplier(() -> new Authenticator()
{
    public void onConnectRequest(...) { session.response(...); /* accept */ }
    public void onChallengeResponse(...) { }
    public void onConnectedSession(Session session) { session.accept(); }
    public void onChallengedSession(Session session) { }
});
Defensive patterns

Strategy: validation

Validate before calling

Authenticator a = ctx.authenticatorSupplier().get();
if (a == null)
{
    throw new IllegalStateException("authenticatorSupplier must return a non-null Authenticator");
}

Prevention

When it happens

Trigger: Launching Archive with an authenticatorSupplier whose get() returns null (e.g. a lambda that fails to instantiate, or a default supplier returning null).

Common situations: Custom AuthenticationSupplier implementations with broken lazy initialization;DI frameworks injecting null when no bean is defined.

Understand the failure class

Related errors


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

Appendix: source

Thrown at aeron-archive/src/main/java/io/aeron/archive/ArchiveConductor.java:212

        aeron = ctx.aeron();
        aeronAgentInvoker = aeron.conductorAgentInvoker();
        driverAgentInvoker = ctx.mediaDriverAgentInvoker();
        epochClock = ctx.epochClock();
        nanoClock = ctx.nanoClock();
        archiveDir = ctx.archiveDir();
        connectTimeoutMs = TimeUnit.NANOSECONDS.toMillis(ctx.connectTimeoutNs());
        sessionLivenessCheckIntervalMs = TimeUnit.NANOSECONDS.toMillis(ctx.sessionLivenessCheckIntervalNs());
        catalog = ctx.catalog();
        markFile = ctx.archiveMarkFile();
        dutyCycleTracker = ctx.conductorDutyCycleTracker();
        cachedEpochClock.update(epochClock.time());

        random = ctx.secureRandom();

        authenticator = ctx.authenticatorSupplier().get();
        if (null == authenticator)
        {
            throw new ArchiveException("authenticator cannot be null");
        }

        authorisationService = ctx.authorisationServiceSupplier().get();
        if (null == authorisationService)
        {
            throw new ArchiveException("authorisation service cannot be null");
        }

        unavailableCounterHandlerRegistrationId = aeron.addUnavailableCounterHandler(this);
        closeHandlerRegistrationId = aeron.addCloseHandler(this::abort);

        recordingEventsProxy = ctx.recordingEventsEnabled() ? new RecordingEventsProxy(
            aeron.addExclusivePublication(ctx.recordingEventsChannel(), ctx.recordingEventsStreamId())) : null;

        if (ctx.controlChannelEnabled())
        {
            final ChannelUri controlChannelUri = ChannelUri.parse(ctx.controlChannel());
            controlChannelUri.put(CommonContext.SPARSE_PARAM_NAME, Boolean.toString(ctx.controlTermBufferSparse()));

View on GitHub (pinned to 6d60124e15)