apache/rocketmq · error · AclException

settings command doesn't have publishing or subscription.

Error message

settings command doesn't have publishing or subscription.

What it means

Thrown by newContext(Metadata, TelemetryCommand) when a TelemetryCommand of the SETTINGS case carries neither a publishing nor a subscription settings section — AclException('settings command doesn't have publishing or subscription.'). The telemetry settings command is how a gRPC client declares its publish/subscribe topics and groups; the authorization builder derives contexts from those sections, so a SETTINGS command with neither is malformed (note: unlike most errors here this is an AclException, not AuthorizationException).

Source

Thrown at auth/src/main/java/org/apache/rocketmq/auth/authorization/builder/DefaultAuthorizationContextBuilder.java:750

        if (StringUtils.isBlank(topic.getName())) {
            throw new AuthorizationException("topic is null.");
        }
        Subject subject = null;
        if (metadata.containsKey(GrpcConstants.AUTHORIZATION_AK)) {
            subject = User.of(metadata.get(GrpcConstants.AUTHORIZATION_AK));
        }
        Resource resource = Resource.ofTopic(topic.getName());
        String sourceIp = StringUtils.substringBeforeLast(metadata.get(GrpcConstants.REMOTE_ADDRESS), CommonConstants.COLON);
        DefaultAuthorizationContext context = DefaultAuthorizationContext.of(subject, resource, Arrays.asList(Action.PUB, Action.SUB), sourceIp);
        return Collections.singletonList(context);
    }

    private static List<DefaultAuthorizationContext> newContext(Metadata metadata, TelemetryCommand request) {
        if (request.getCommandCase() != TelemetryCommand.CommandCase.SETTINGS) {
            return null;
        }
        if (!request.getSettings().hasPublishing() && !request.getSettings().hasSubscription()) {
            throw new AclException("settings command doesn't have publishing or subscription.");
        }
        List<DefaultAuthorizationContext> result = new ArrayList<>();
        if (request.getSettings().hasPublishing()) {
            List<apache.rocketmq.v2.Resource> topicList = request.getSettings().getPublishing().getTopicsList();
            for (apache.rocketmq.v2.Resource topic : topicList) {
                result.addAll(newPubContext(metadata, topic));
            }
        }
        if (request.getSettings().hasSubscription()) {
            Subscription subscription = request.getSettings().getSubscription();
            result.addAll(newSubContexts(metadata, ResourceType.GROUP, subscription.getGroup()));
            for (SubscriptionEntry entry : subscription.getSubscriptionsList()) {
                result.addAll(newSubContexts(metadata, ResourceType.TOPIC, entry.getTopic()));
            }
        }
        return result;
    }

View on GitHub (pinned to 293f588571)

Solutions

  1. Include at least one of publishing or subscription in the Settings message: setSettings(Settings.newBuilder().setPublishing(...)) or setSubscription(...).
  2. Do not send SETTINGS telemetry commands from custom code — let the official client manage the telemetry session.
  3. Upgrade custom shims to match the client protocol version that always populates one section.

Example fix

// before
TelemetryCommand cmd = TelemetryCommand.newBuilder()
    .setSettings(Settings.newBuilder().build()).build(); // neither section

// after
TelemetryCommand cmd = TelemetryCommand.newBuilder()
    .setSettings(Settings.newBuilder()
        .setPublishing(Publishing.newBuilder()
            .addTopics(Resource.newBuilder().setName(topic))))
    .build();
Defensive patterns

Strategy: validation

Validate before calling

Settings s = request.getSettings();
if (request.getCommandCase() == TelemetryCommand.CommandCase.SETTINGS
    && !s.hasPublishing() && !s.hasSubscription()) {
    throw new IllegalArgumentException("SETTINGS needs publishing or subscription");
}

Type guard

static boolean isAuthorizableSettings(Settings s) {
    return s != null && (s.hasPublishing() || s.hasSubscription());
}

Try / catch

try { client.telemetry(cmd); }
catch (AclException e) {
    if (e.getMessage().contains("publishing or subscription")) { rebuildWithPublishing(); return; }
    throw e;
}

Prevention

When it happens

Trigger: Sending TelemetryCommand.newBuilder().setSettings(Settings.newBuilder().build()) — i.e. a SETTINGS command with an empty Settings message, with only non-publish/subscription settings (e.g. just a backoff policy), or built by custom client code that never sets publishing/subscription. Standard clients always include one of the two.

Common situations: Hand-written gRPC clients or protocol shims issuing a bare SETTINGS telemetry command; client versions that send metrics/stream-level settings without publishing or subscription during connection setup; test harnesses replaying captured telemetry commands with sections stripped.

Related errors


AI-assisted analysis of apache/rocketmq@293f588571 (2026-08-14). Data as JSON: /api/errors/449dd1e3e625ff8d. Report an issue: GitHub.