apache/rocketmq · error · MQClientException

The specified topic[%s] contains illegal characters, allowin

Error message

The specified topic[%s] contains illegal characters, allowing only %s

What it means

Validators.checkTopic rejects topics containing characters outside ^[%|a-zA-Z0-9_-]+$ (checked via isTopicOrGroupIllegal). Dots, colons, spaces, slashes, and unicode are illegal; '%' is allowed because system topics like %RETRY% and %DLQ% use it.

Source

Thrown at client/src/main/java/org/apache/rocketmq/client/Validators.java:106

        String lmqPath = msg.getUserProperty(MessageConst.PROPERTY_INNER_MULTI_DISPATCH);
        if (StringUtils.contains(lmqPath, File.separator)) {
            throw new MQClientException(ResponseCode.MESSAGE_ILLEGAL,
                "INNER_MULTI_DISPATCH " + lmqPath + " can not contains " + File.separator + " character");
        }
    }

    public static void checkTopic(String topic) throws MQClientException {
        if (UtilAll.isBlank(topic)) {
            throw new MQClientException("The specified topic is blank", null);
        }

        if (topic.length() > TOPIC_MAX_LENGTH) {
            throw new MQClientException(
                String.format("The specified topic is longer than topic max length %d.", TOPIC_MAX_LENGTH), null);
        }

        if (isTopicOrGroupIllegal(topic)) {
            throw new MQClientException(String.format(
                    "The specified topic[%s] contains illegal characters, allowing only %s", topic,
                    "^[%|a-zA-Z0-9_-]+$"), null);
        }
    }

    public static void isSystemTopic(String topic) throws MQClientException {
        if (TopicValidator.isSystemTopic(topic)) {
            throw new MQClientException(
                    String.format("The topic[%s] is conflict with system topic.", topic), null);
        }
    }

    public static void isNotAllowedSendTopic(String topic) throws MQClientException {
        if (TopicValidator.isNotAllowedSendTopic(topic)) {
            throw new MQClientException(
                    String.format("Sending message to topic[%s] is forbidden.", topic), null);
        }
    }

View on GitHub (pinned to 293f588571)

Solutions

  1. Normalize topic names to letters, digits, '-', '_' — replace '.' with '-' or '_'.
  2. Add a startup regex check on configured topics: topic.matches("^[%|a-zA-Z0-9_-]+$").
  3. Trim whitespace when topics come from user or config input.

Example fix

// before
String topic = "order.created.v2";

// after
String topic = "order-created-v2";
Defensive patterns

Strategy: validation

Validate before calling

static boolean legalTopicName(String t) {
    return t != null && t.matches("^[%|a-zA-Z0-9_-]+$");
}

Prevention

When it happens

Trigger: Creating/sending with a topic like 'order.created.v2' (dot), 'app:orders' (colon), or '订单' (unicode); topics derived from URLs or free-form strings.

Common situations: Porting Kafka-style dotted topic names; using domain event names verbatim ('order.created'); copy-paste introducing invisible whitespace.

Related errors


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