alibaba/spring-cloud-alibaba · error · IllegalArgumentException

topic must not be empty

Error message

topic must not be empty

What it means

getAndWrapMessage throws IllegalArgumentException('topic must not be empty') if the resolved topic is null or blank. RocketMQ cannot address a message without a topic, so the binder refuses to construct the Message.

Source

Thrown at spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/support/RocketMQMessageConverterSupport.java:141

				if (null == jsonObj) {
					throw new RuntimeException(String.format(
							"empty after conversion [messageConverter:%s,payloadClass:%s,payloadObj:%s]",
							MESSAGE_CONVERTER.getClass(), payloadObj.getClass(),
							payloadObj));
				}
				payloads = jsonObj.getBytes(charset);
			}
		}
		catch (Exception e) {
			throw new RuntimeException("convert to RocketMQ message failed.", e);
		}
		return getAndWrapMessage(topic, message.getHeaders(), payloads);
	}

	private static org.apache.rocketmq.common.message.Message getAndWrapMessage(
			String topic, MessageHeaders headers, byte[] payloads) {
		if (topic == null || topic.length() < 1) {
			throw new IllegalArgumentException("topic must not be empty");
		}
		if (payloads == null || payloads.length < 1) {
			throw new IllegalArgumentException("payload must not be empty");
		}
		org.apache.rocketmq.common.message.Message rocketMsg = new org.apache.rocketmq.common.message.Message(
				topic, payloads);
		if (Objects.nonNull(headers) && !headers.isEmpty()) {
			Object tag = headers.getOrDefault(Headers.TAGS,
					headers.get(toRocketHeaderKey(Headers.TAGS)));
			if (!ObjectUtils.isEmpty(tag)) {
				rocketMsg.setTags(String.valueOf(tag));
			}

			Object keys = headers.getOrDefault(Headers.KEYS,
					headers.get(toRocketHeaderKey(Headers.KEYS)));
			if (!ObjectUtils.isEmpty(keys)) {
				rocketMsg.setKeys(keys.toString());
			}

View on GitHub (pinned to 115d590110)

Solutions

  1. Set `spring.cloud.stream.bindings.<output>.destination=<topic>`.
  2. Resolve any unresolved `${...}` placeholders in the destination.
  3. For programmatic sends, pass a non-blank topic.

Example fix

// before
spring:
  cloud:
    stream:
      bindings:
        out1:
          destination: ${MISSING_TOPIC}   # unresolved -> blank -> [137]
# after
spring:
  cloud:
    stream:
      bindings:
        out1:
          destination: order-events
Defensive patterns

Strategy: validation

Validate before calling

// Reject blank topics before conversion.
if (topic == null || topic.isBlank()) {
    throw new IllegalArgumentException("RocketMQ topic is blank; set bindings.<output>.destination (avoids [137])");
}

Prevention

When it happens

Trigger: convertMessage2MQ is called with a null/empty topic - e.g. destination.getName() is blank, or a programmatic send omits the topic.

Common situations: Outbound binding destination not configured (blank `destination`); the destination resolved to empty due to a placeholder that was never substituted; a programmatic producer send with no topic.

Related errors


AI-assisted analysis of alibaba/spring-cloud-alibaba@115d590110 (2026-08-14). Data as JSON: /api/errors/16966d192c5a2104. Report an issue: GitHub.