{"record":{"id":"449dd1e3e625ff8d","repo":"apache/rocketmq","slug":"settings-command-doesn-t-have-publishing-or-subscr","errorCode":null,"errorMessage":"settings command doesn't have publishing or subscription.","messagePattern":"settings command doesn't have publishing or subscription\\.","errorType":"exception","errorClass":"AclException","httpStatus":null,"severity":"error","filePath":"auth/src/main/java/org/apache/rocketmq/auth/authorization/builder/DefaultAuthorizationContextBuilder.java","lineNumber":750,"sourceCode":"        if (StringUtils.isBlank(topic.getName())) {\n            throw new AuthorizationException(\"topic is null.\");\n        }\n        Subject subject = null;\n        if (metadata.containsKey(GrpcConstants.AUTHORIZATION_AK)) {\n            subject = User.of(metadata.get(GrpcConstants.AUTHORIZATION_AK));\n        }\n        Resource resource = Resource.ofTopic(topic.getName());\n        String sourceIp = StringUtils.substringBeforeLast(metadata.get(GrpcConstants.REMOTE_ADDRESS), CommonConstants.COLON);\n        DefaultAuthorizationContext context = DefaultAuthorizationContext.of(subject, resource, Arrays.asList(Action.PUB, Action.SUB), sourceIp);\n        return Collections.singletonList(context);\n    }\n\n    private static List<DefaultAuthorizationContext> newContext(Metadata metadata, TelemetryCommand request) {\n        if (request.getCommandCase() != TelemetryCommand.CommandCase.SETTINGS) {\n            return null;\n        }\n        if (!request.getSettings().hasPublishing() && !request.getSettings().hasSubscription()) {\n            throw new AclException(\"settings command doesn't have publishing or subscription.\");\n        }\n        List<DefaultAuthorizationContext> result = new ArrayList<>();\n        if (request.getSettings().hasPublishing()) {\n            List<apache.rocketmq.v2.Resource> topicList = request.getSettings().getPublishing().getTopicsList();\n            for (apache.rocketmq.v2.Resource topic : topicList) {\n                result.addAll(newPubContext(metadata, topic));\n            }\n        }\n        if (request.getSettings().hasSubscription()) {\n            Subscription subscription = request.getSettings().getSubscription();\n            result.addAll(newSubContexts(metadata, ResourceType.GROUP, subscription.getGroup()));\n            for (SubscriptionEntry entry : subscription.getSubscriptionsList()) {\n                result.addAll(newSubContexts(metadata, ResourceType.TOPIC, entry.getTopic()));\n            }\n        }\n        return result;\n    }\n","sourceCodeStart":732,"sourceCodeEnd":768,"githubUrl":"https://github.com/apache/rocketmq/blob/293f5885719fc4aa3619446a1900f58ccfcfdd29/auth/src/main/java/org/apache/rocketmq/auth/authorization/builder/DefaultAuthorizationContextBuilder.java#L732-L768","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","solutions":["Include at least one of publishing or subscription in the Settings message: setSettings(Settings.newBuilder().setPublishing(...)) or setSubscription(...).","Do not send SETTINGS telemetry commands from custom code — let the official client manage the telemetry session.","Upgrade custom shims to match the client protocol version that always populates one section."],"exampleFix":"// before\nTelemetryCommand cmd = TelemetryCommand.newBuilder()\n    .setSettings(Settings.newBuilder().build()).build(); // neither section\n\n// after\nTelemetryCommand cmd = TelemetryCommand.newBuilder()\n    .setSettings(Settings.newBuilder()\n        .setPublishing(Publishing.newBuilder()\n            .addTopics(Resource.newBuilder().setName(topic))))\n    .build();","handlingStrategy":"validation","validationCode":"Settings s = request.getSettings();\nif (request.getCommandCase() == TelemetryCommand.CommandCase.SETTINGS\n    && !s.hasPublishing() && !s.hasSubscription()) {\n    throw new IllegalArgumentException(\"SETTINGS needs publishing or subscription\");\n}","typeGuard":"static boolean isAuthorizableSettings(Settings s) {\n    return s != null && (s.hasPublishing() || s.hasSubscription());\n}","tryCatchPattern":"try { client.telemetry(cmd); }\ncatch (AclException e) {\n    if (e.getMessage().contains(\"publishing or subscription\")) { rebuildWithPublishing(); return; }\n    throw e;\n}","preventionTips":["Let the official client own the telemetry session","Always set publishing or subscription on SETTINGS commands","Do not replay captured telemetry commands with sections stripped"],"tags":["rocketmq","grpc","telemetry","authorization","settings"],"backgroundTag":null,"analyzedSha":"293f5885719fc4aa3619446a1900f58ccfcfdd29","analyzedAt":"2026-08-14T11:50:13.822Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}