unbridled-41 opened a new issue, #4735:
URL: https://github.com/apache/rocketmq-dashboard/issues/4735
### Studio Version
branch: rocketmq-studio
git commit id: 7ce9a68215c4cd1c7025013d02135b43b6aa6ba1
### Problem
The AI redelivery tool (`rmq.message.redelivery`) publishes the message
explorer's **display projection** instead of the stored payload, so a
redelivered copy silently differs from the source message:
- the body is cut at 64 KiB
(`RocketMQMessageProvider.MAX_BODY_DISPLAY_BYTES`,
`provider/apache/RocketMQMessageProvider.java:87`),
- a body that is not valid UTF-8 is replaced by the Base64 text of at most
48 KiB (`displayBody`, `:836-861`),
- the user-property map is capped at 64 entries and 1024 code points per
value (`MessagePropertyDisplay.limitProperties`,
`common/util/MessagePropertyDisplay.java:35,43,63`).
Chain: `MessageRedeliveryToolHandler.execute`
(`ops/ai/tool/handler/message/MessageRedeliveryToolHandler.java:63,76`) →
`MetadataService.redeliverMessage(String,String,String,String,String)`
(`instance/topic/MetadataService.java:293-298`) → `findMessageForRedelivery`
(`:342-350`) → `MessageService.queryMessages` →
`RocketMQMessageProvider.toRecordVO`
(`provider/apache/RocketMQMessageProvider.java:811-832`, display caps applied
at `:813,:824`) → `MetadataService.redeliverMessage(..., MessageRecordVO, ...)`
(`:300-315`) publishes `original.getBody()`.
The tool's own plan text promises the opposite: "Publishes a new message
containing the source payload and properties"
(`MessageRedeliveryToolHandler.java:43-45`), and `findMessageForRedelivery` is
documented as loading "the exact source message" (`MetadataService.java:341`).
The sibling DLQ path does use the raw bytes
(`provider/apache/RocketMQDLQProvider.java:583`).
Trigger (deterministic): redeliver any message whose body is larger than 64
KiB, or whose body is not valid UTF-8 text, or that carries more than 64 user
properties. The copy is published without any warning that it is a partial
copy; nothing in the response (`SendMessageVO`) indicates the payload was
rewritten.
### Evidence
-
`server/src/main/java/org/apache/rocketmq/studio/instance/topic/MetadataService.java:293-298`
— the five-argument entry point loads the source through
`findMessageForRedelivery` and passes that VO straight to the publisher.
-
`server/src/main/java/org/apache/rocketmq/studio/instance/topic/MetadataService.java:342-350`
— `findMessageForRedelivery` is `messageService.queryMessages(...)`, i.e. the
same display projection the message explorer renders.
-
`server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQMessageProvider.java:811-832`
— `toRecordVO` builds `body(displayBody.value())`, `bodyEncoding(...)`,
`bodyTruncated(...)`, `properties(displayProperties)`,
`propertiesTruncated(...)`; `displayBody` (`:836-861`) truncates at 64 KiB / 48
KiB and Base64-encodes non-UTF-8 bodies.
-
`server/src/main/java/org/apache/rocketmq/studio/common/util/MessagePropertyDisplay.java:35,43,63`
— the property caps and their stated purpose ("rendering limits for message
property maps").
- Regression test added with this report (fails on 7ce9a682): a source VO
with `bodyTruncated=true`, one with `bodyEncoding="BASE64"`, and one with
`propertiesTruncated=true` are each published today
(`verify(provider).sendMessage(...)` succeeds, body = the truncated string);
the tests expect a refusal instead.
### Impact
A redelivered message is a corrupted copy: for a 100 KiB body only the first
65536 bytes are republished, a binary payload is republished as Base64 text
(different bytes, different semantics for the consumer), and properties past
the display cap disappear. The operation reports success, so the loss is only
discoverable downstream — after the consumer has already processed a message
that is not the one it was sent.
### Expected behavior
`rmq.message.redelivery` either publishes the exact stored payload, or
refuses the operation with a clear 4xx when the source cannot be reproduced
exactly (truncated body, Base64-projected binary body, capped property map) —
it must not publish a silently rewritten copy. The refusal path keeps
`MessageRecordVO`'s display contract unchanged for the message explorer, which
is where the caps belong.
### Related work
- #4606 (merged, 5b761df8) — the AI conversation platform that introduced
`rmq.message.redelivery` and its plan text.
-
`server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQDLQProvider.java:583`
— the DLQ resend path already uses the raw `deadLetter.getBody()`, which is
the behavior this path was expected to match.
- The display caps are shared deliberately (`MessagePropertyDisplay`
javadoc): the defect is that a *display* projection is used as a *write*
payload, not that the caps exist.
#
## PR
Fix: TBD.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]