apache/pulsar · error · IllegalArgumentException

brokerDeleteInactiveTopicsEnabled and brokerCloseInactiveTop

Error message

brokerDeleteInactiveTopicsEnabled and brokerCloseInactiveTopicsEnabled are mutually exclusive. Enable at most one of them.

What it means

This IllegalArgumentException is thrown at broker startup when both brokerDeleteInactiveTopicsEnabled and brokerCloseInactiveTopicsEnabled are set to true. The two features are alternative ways of reclaiming inactive topics (deleting vs closing/unloading them), so enabling both is contradictory and the broker refuses to start rather than picking one arbitrarily.

Source

Thrown at pulsar-broker/src/main/java/org/apache/pulsar/broker/PulsarService.java:907

                    >= (config.getDefaultRetentionSizeInMB() * 1024L * 1024L)) {
                throw new IllegalArgumentException(String.format("The retention size must > the backlog quota limit "
                                + "size, but the configured backlog quota limit bytes is %d, the retention size is %d",
                        config.getBacklogQuotaDefaultLimitBytes(),
                        config.getDefaultRetentionSizeInMB() * 1024L * 1024L));
            }

            if (config.getDefaultRetentionTimeInMinutes() > 0
                    && config.getBacklogQuotaDefaultLimitSecond() > 0
                    && config.getBacklogQuotaDefaultLimitSecond() >= config.getDefaultRetentionTimeInMinutes() * 60) {
                throw new IllegalArgumentException(String.format("The retention time must > the backlog quota limit "
                                + "time, but the configured backlog quota limit time duration is %d, "
                                + "the retention time duration is %d",
                        config.getBacklogQuotaDefaultLimitSecond(),
                        config.getDefaultRetentionTimeInMinutes() * 60));
            }

            if (config.isBrokerDeleteInactiveTopicsEnabled() && config.isBrokerCloseInactiveTopicsEnabled()) {
                throw new IllegalArgumentException(
                        "brokerDeleteInactiveTopicsEnabled and brokerCloseInactiveTopicsEnabled are mutually "
                                + "exclusive. Enable at most one of them.");
            }

            if (config.isBrokerCloseInactiveTopicsEnabled()
                    && config.getBrokerDeleteInactiveTopicsMode()
                            != InactiveTopicDeleteMode.delete_when_no_subscriptions) {
                throw new IllegalArgumentException(
                        "brokerCloseInactiveTopicsEnabled only supports brokerDeleteInactiveTopicsMode="
                                + "delete_when_no_subscriptions. Under delete_when_subscriptions_caught_up a topic "
                                + "whose subscriptions are caught up is inactive even while consumers are still "
                                + "connected, so closing it would repeatedly unload and reload the topic.");
            }

            openTelemetryTopicStats = new OpenTelemetryTopicStats(this);
            openTelemetryConsumerStats = new OpenTelemetryConsumerStats(this);
            openTelemetryProducerStats = new OpenTelemetryProducerStats(this);
            openTelemetryReplicatorStats = new OpenTelemetryReplicatorStats(this);

View on GitHub (pinned to 820761864e)

Solutions

  1. Disable one of the two flags: set brokerDeleteInactiveTopicsEnabled=false if you want closing, or brokerCloseInactiveTopicsEnabled=false if you want deletion.
  2. Decide based on goal: use delete to remove inactive topics entirely, use close to unload them (with a grace period) while keeping metadata.
  3. Audit broker.conf, env-var overrides, and framework templates so only one flag is set to true.
  4. Restart the broker and confirm startup passes validation.

Example fix

// before (broker.conf)
brokerDeleteInactiveTopicsEnabled=true
brokerCloseInactiveTopicsEnabled=true
// after
brokerDeleteInactiveTopicsEnabled=false
brokerCloseInactiveTopicsEnabled=true
Defensive patterns

Strategy: validation

Validate before calling

// before broker start (Java)
if (conf.isBrokerDeleteInactiveTopicsEnabled() && conf.isBrokerCloseInactiveTopicsEnabled()) {
    throw new IllegalArgumentException(
        "Enable at most one of brokerDeleteInactiveTopicsEnabled / brokerCloseInactiveTopicsEnabled");
}

Try / catch

try {
    pulsar.start();
} catch (IllegalArgumentException e) {
    if (e.getMessage().contains("brokerDeleteInactiveTopicsEnabled and brokerCloseInactiveTopicsEnabled are mutually exclusive")) {
        // fix broker.conf: set exactly one of the two flags to true, then retry
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Starting a broker with isBrokerDeleteInactiveTopicsEnabled()==true AND isBrokerCloseInactiveTopicsEnabled()==true in the service configuration, e.g. after enabling the newer close-inactive-topics feature without disabling the legacy delete flag.

Common situations: Configuration merges or version upgrades where a new brokerCloseInactiveTopicsEnabled=true line is added while the older brokerDeleteInactiveTopicsEnabled=true is left in place; templated Helm/env config that sets both flags.

Related errors


AI-assisted analysis of apache/pulsar@820761864e (2026-09-06). Data as JSON: /api/errors/3162a1491db95b55. Report an issue: GitHub.