apache/rocketmq · error · AuthorizationException

cold data flow config is empty.

Error message

cold data flow config is empty.

What it means

Thrown when handling UPDATE_COLD_DATA_FLOW_CTR_CONFIG: the request body is decoded as text and parsed into java.util.Properties via MixAll.string2Properties, and the result is null (unparseable) or has no keys. Because each property name becomes a consumer-group Resource to authorize an UPDATE against, an empty property set cannot produce any authorization context and the request fails with AuthorizationException.

Source

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

                    if (CollectionUtils.isEmpty(topicListBody.getTopicConfigList())) {
                        throw new AuthorizationException("topic list is empty.");
                    }
                    Set<String> topicListResources = new LinkedHashSet<>();
                    for (TopicConfig topicConfig : topicListBody.getTopicConfigList()) {
                        if (topicConfig == null) {
                            throw new AuthorizationException("topic config is null.");
                        }
                        String topicName = requireResource(topicConfig.getTopicName(), "topic");
                        Resource resource = NamespaceUtil.isRetryTopic(topicName)
                            ? Resource.ofGroup(topicName) : Resource.ofTopic(topicName);
                        addUniqueContext(result, topicListResources, subject, resource, Action.CREATE, sourceIp);
                    }
                    break;
                case RequestCode.UPDATE_COLD_DATA_FLOW_CTR_CONFIG:
                    Properties properties = MixAll.string2Properties(
                        decodeRequiredText(command, "cold data flow config"));
                    if (properties == null || properties.isEmpty()) {
                        throw new AuthorizationException("cold data flow config is empty.");
                    }
                    Set<String> coldDataResources = new LinkedHashSet<>();
                    for (String consumerGroup : properties.stringPropertyNames()) {
                        addUniqueContext(result, coldDataResources, subject,
                            Resource.ofGroup(requireResource(consumerGroup, "consumer group")),
                            Action.UPDATE, sourceIp);
                    }
                    break;
                case RequestCode.REMOVE_COLD_DATA_FLOW_CTR_CONFIG:
                    group = Resource.ofGroup(requireResource(
                        decodeRequiredText(command, "consumer group"), "consumer group"));
                    result.add(DefaultAuthorizationContext.of(subject, group, Action.UPDATE, sourceIp));
                    break;
                case RequestCode.UPDATE_AND_CREATE_SUBSCRIPTIONGROUP:
                    SubscriptionGroupConfig subscriptionGroupConfig =
                        RemotingSerializable.decode(command.getBody(), SubscriptionGroupConfig.class);
                    if (subscriptionGroupConfig == null
                        || StringUtils.isBlank(subscriptionGroupConfig.getGroupName())) {

View on GitHub (pinned to 293f588571)

Solutions

  1. Send the body as standard properties text: one 'consumerGroup=anything' line per group, newline separated.
  2. Confirm the client version's body format matches the broker's MixAll.string2Properties expectation (java.util.Properties.load semantics).
  3. Test-serialize the properties string locally and assert Properties#stringPropertyNames() is non-empty before sending.

Example fix

// before
String body = String.join(",", groups); // unparseable as properties
command.setBody(body.getBytes(UTF_8));

// after
StringBuilder sb = new StringBuilder();
for (String g : groups) { sb.append(g).append("=1\n"); }
if (sb.length() == 0) { return; }
command.setBody(sb.toString().getBytes(UTF_8));
Defensive patterns

Strategy: validation

Validate before calling

String text = toPropertiesText(groups);
Properties check = MixAll.string2Properties(text);
if (check == null || check.isEmpty()) { throw new IllegalArgumentException("bad cold data config text"); }

Try / catch

try { broker.updateColdDataFlowCtrConfig(text); }
catch (AuthorizationException e) {
    if (e.getMessage().contains("cold data flow config is empty")) { rebuildBodyAsProperties(); return; }
    throw e;
}

Prevention

When it happens

Trigger: Sending RequestCode.UPDATE_COLD_DATA_FLOW_CTR_CONFIG whose body text is empty after trim, is not valid key=value properties syntax (string2Properties returns null), or is a properties string with zero entries. The earlier decodeRequiredText already guarantees the body bytes are non-empty, so this fires on 'non-empty but unparseable/empty-as-properties' input.

Common situations: Body encoded as JSON or a bare group name instead of 'key=value' lines; properties string built with String.join(",") instead of newlines; double-encoding (whole properties object toString'd) after a client upgrade changed the body format.

Related errors


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