{"record":{"id":"2959920504e4ae47","repo":"apache/rocketmq","slug":"topic-is-null","errorCode":null,"errorMessage":"topic is null.","messagePattern":"topic is null\\.","errorType":"exception","errorClass":"AuthorizationException","httpStatus":null,"severity":"error","filePath":"auth/src/main/java/org/apache/rocketmq/auth/authorization/builder/DefaultAuthorizationContextBuilder.java","lineNumber":733,"sourceCode":"                        }\n                    }\n                } finally {\n                    field.setAccessible(false);\n                }\n            }\n        }\n\n        if (CollectionUtils.isEmpty(result) && resource != null) {\n            result.add(DefaultAuthorizationContext.of(subject, resource, Arrays.asList(actions), sourceIp));\n        }\n\n        return result;\n    }\n\n    private List<DefaultAuthorizationContext> newContext(Metadata metadata, QueryRouteRequest request) {\n        apache.rocketmq.v2.Resource topic = request.getTopic();\n        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        }","sourceCodeStart":715,"sourceCodeEnd":751,"githubUrl":"https://github.com/apache/rocketmq/blob/293f5885719fc4aa3619446a1900f58ccfcfdd29/auth/src/main/java/org/apache/rocketmq/auth/authorization/builder/DefaultAuthorizationContextBuilder.java#L715-L751","documentation":"Thrown by the gRPC path newContext(Metadata, QueryRouteRequest): the topic Resource in a QueryRouteRequest has a blank name, so AuthorizationException('topic is null.') is raised. Before the broker can authorize route discovery, it must know which topic to authorize PUB/SUB on — both actions are attached to this single topic resource — so a nameless topic cannot proceed.","triggerScenarios":"A gRPC QueryRouteRequest where topic.name is unset, empty, or whitespace: client code building Resource.newBuilder() without setName, or copying a Resource proto with a missing name field. Note the null-check is only on getName() blankness, not on topic == null itself (calling request.getTopic() on an unset proto returns a default instance).","commonSituations":"New gRPC/protobuf clients forgetting setName on the topic resource; templating code that renders an empty topic string; topic names read from config that is missing in one environment; a shim layer mapping amqp/jms topic properties to the proto and dropping nulls to empty.","solutions":["Set topic.setName(topicName) on the QueryRouteRequest's Resource before sending, and validate the name is non-blank client-side.","If the topic comes from config, fail fast at startup when it is blank rather than at route query time.","Use the official rocketmq-client-java producer/consumer, which validates the topic before issuing QueryRoute."],"exampleFix":"// before\nResource topic = Resource.newBuilder().build(); // name unset\nQueryRouteRequest req = QueryRouteRequest.newBuilder().setTopic(topic).build();\n\n// after\nif (CharSequenceUtil.isBlank(topicName)) throw new IllegalArgumentException(\"topic required\");\nResource topic = Resource.newBuilder().setName(topicName).build();","handlingStrategy":"validation","validationCode":"if (topicName == null || topicName.isBlank()) {\n    throw new IllegalArgumentException(\"topic name required for queryRoute\");\n}\nQueryRouteRequest req = QueryRouteRequest.newBuilder()\n    .setTopic(Resource.newBuilder().setName(topicName)).build();","typeGuard":"static boolean hasTopicName(apache.rocketmq.v2.Resource r) {\n    return r != null && !r.getName().isBlank();\n}","tryCatchPattern":null,"preventionTips":["Validate topic config at client startup","Always call setName on Resource builders","Fail fast on blank topics instead of sending the RPC"],"tags":["rocketmq","grpc","authorization","query-route","validation"],"backgroundTag":null,"analyzedSha":"293f5885719fc4aa3619446a1900f58ccfcfdd29","analyzedAt":"2026-08-14T11:50:13.822Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}