apache/rocketmq · error · AuthorizationException

topic header is null.

Error message

topic header is null.

What it means

Thrown for UPDATE_AND_CREATE_STATIC_TOPIC when command.decodeCommandCustomHeader(CreateTopicRequestHeader.class) returns null — i.e. the remoting command lacks the custom header fields needed to build a CreateTopicRequestHeader. The topic name from that header is the Resource the CREATE action is authorized against, so a null header cannot be authorized and the request fails.

Source

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

                        command, SubscriptionGroupList.class, "subscription group list");
                    if (CollectionUtils.isEmpty(subscriptionGroupList.getGroupConfigList())) {
                        throw new AuthorizationException("subscription group list is empty.");
                    }
                    Set<String> subscriptionGroupResources = new LinkedHashSet<>();
                    for (SubscriptionGroupConfig groupConfig : subscriptionGroupList.getGroupConfigList()) {
                        if (groupConfig == null) {
                            throw new AuthorizationException("subscription group config is null.");
                        }
                        addUniqueContext(result, subscriptionGroupResources, subject,
                            Resource.ofGroup(requireResource(groupConfig.getGroupName(), "consumer group")),
                            Action.CREATE, sourceIp);
                    }
                    break;
                case RequestCode.UPDATE_AND_CREATE_STATIC_TOPIC:
                    CreateTopicRequestHeader createTopicRequestHeader =
                        command.decodeCommandCustomHeader(CreateTopicRequestHeader.class);
                    if (createTopicRequestHeader == null) {
                        throw new AuthorizationException("topic header is null.");
                    }
                    String staticTopic = requireResource(createTopicRequestHeader.getTopic(), "topic");
                    TopicQueueMappingDetail mappingDetail = decodeRequiredBody(
                        command, TopicQueueMappingDetail.class, "topic queue mapping");
                    if (!StringUtils.equals(
                        staticTopic, requireResource(mappingDetail.getTopic(), "mapping topic"))) {
                        throw new AuthorizationException("mapping topic does not match topic header.");
                    }
                    topic = Resource.ofTopic(staticTopic);
                    result.add(DefaultAuthorizationContext.of(subject, topic, Action.CREATE, sourceIp));
                    break;
                case RequestCode.GET_BROKER_CONFIG:
                case RequestCode.GET_BROKER_RUNTIME_INFO:
                case RequestCode.GET_ALL_CONSUMER_OFFSET:
                case RequestCode.GET_TIMER_CHECK_POINT:
                case RequestCode.GET_ALL_DELAY_OFFSET:
                case RequestCode.GET_BROKER_HA_STATUS:
                case RequestCode.GET_BROKER_EPOCH_CACHE:

View on GitHub (pinned to 293f588571)

Solutions

  1. Construct the request via the standard client API (e.g. AdminBrokerProcessor / mqadmin createTopic -c) so the CreateTopicRequestHeader is always attached.
  2. If building RemotingCommand manually, call command.setCommandCustomHeader(new CreateTopicRequestHeader(topic...)) before sending.
  3. Check that the 'topic' extField is present and the client version matches the broker's static-topic support.

Example fix

// before
RemotingCommand cmd = RemotingCommand.createRequestCommand(
    RequestCode.UPDATE_AND_CREATE_STATIC_TOPIC, null); // no header

// after
CreateTopicRequestHeader h = new CreateTopicRequestHeader();
h.setTopic(topic);
RemotingCommand cmd = RemotingCommand.createRequestCommand(
    RequestCode.UPDATE_AND_CREATE_STATIC_TOPIC, h);
Defensive patterns

Strategy: validation

Validate before calling

RemotingCommand cmd = RemotingCommand.createRequestCommand(
    RequestCode.UPDATE_AND_CREATE_STATIC_TOPIC, header);
if (cmd.readCustomHeader() == null) { throw new IllegalStateException("header missing"); }

Try / catch

try { client.invokeSync(addr, cmd, timeout); }
catch (AuthorizationException e) {
    if ("topic header is null.".equals(e.getMessage())) { attachHeaderAndResend(); return; }
    throw e;
}

Prevention

When it happens

Trigger: Sending RequestCode.UPDATE_AND_CREATE_STATIC_TOPIC where the command's extFields do not contain the entries CreateTopicRequestHeader maps (e.g. missing 'topic'), or where the header class cannot be instantiated/populated. Usually means the request was constructed by raw RemotingCommand without setCommandCustomHeader, or by an incompatible client version.

Common situations: Custom tooling that builds RemotingCommand manually for static (migrated) topic creation and forgets the header; version skew where the header field names changed; proxying frameworks that drop extFields.

Related errors


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