[Bug] mqadmin: the declared option set does not match what the commands read (NPE instead of a usage error; the consumer -i mode is unreachable)
维护者通常 1 天内回复
评估
调研方向
Start with the option declarations in tools/src/main/java/org/apache/rocketmq/tools/command/consumer/ConsumerSubCommand.java, ResetMasterFlushOffsetSubCommand, and message/DecodeMessageIdCommond.java, comparing each Option set with the getOptionValue calls in execute(). Linked PR #11411 is already open against this issue, so check it before starting. Done means consumer -i parses, and the other two commands reject a missing -b/-o/-i at parse time.
由索引模型根据 Issue 内容生成。
描述
Before Creating the Bug Report
- I found a bug, not just asking a question, which should be created in GitHub Discussions.
- I have searched the GitHub Issues and GitHub Discussions of this repository and believe that this is not a duplicate.
- I have confirmed that this bug belongs to the current repository, not other repositories of RocketMQ.
Runtime platform environment
OS: any (the mqadmin command line tool)
RocketMQ version
branch: develop
Git commit id: a7edeecfb
JDK Version
Compiler: Temurin 1.8.0_504 (target 1.8, same as CI)
Describe the Bug
I cross-checked every commons-cli Option a subcommand declares against the keys the same command reads (hasOption/getOptionValue) across the 73 SubCommand classes of the tools module. Apart from the static-topic -mf/--mapFile mismatch that is already reported in #11381, three commands still declare an option set that does not match what their execute() needs:
(1) mqadmin consumer: -i is read but never declared, so the single-client mode cannot be used.
ConsumerSubCommand.buildCommandlineOptions only registers -g/--consumerGroup and -s/--jstack (tools/src/main/java/org/apache/rocketmq/tools/command/consumer/ConsumerSubCommand.java:53-64), while execute() branches on the option:
if (!commandLine.hasOption('i')) {
... // every client of the group
} else {
String clientId = commandLine.getOptionValue('i').trim(); // :125
...
}
Because DefaultParser rejects an option that is not registered, mqadmin consumer -g <group> -i <clientId> aborts with Unrecognized option: -i and System.exit(1) (srvutil/.../ServerUtil.java:54-58); the else branch is therefore unreachable dead code and the per-client query the command was written to support cannot be run at all.
(2) mqadmin resetMasterFlushOffset: -b and -o are declared optional but read unconditionally.
Option opt = new Option("b", "brokerAddr", true, "which broker to reset");
opt.setRequired(false); // :41-42
opt = new Option("o", "offset", true, "the offset to reset at");
opt.setRequired(false); // :45-46
...
String brokerAddr = commandLine.getOptionValue('b').trim(); // :60
long masterFlushOffset = Long.parseLong(commandLine.getOptionValue('o').trim()); // :61
With either option omitted the parse succeeds and the command fails with a NullPointerException from the .trim() (there is no fallback for either value): mqadmin resetMasterFlushOffset crashes on -b, mqadmin resetMasterFlushOffset -b 127.0.0.1:10911 crashes on -o, and -o with a non-numeric value gives a NumberFormatException. The exception is wrapped into a SubCommandException and printed as a stack trace by MQAdminStartup (tools/.../command/MQAdminStartup.java:194-196), so the user gets no usage information at all.
(3) mqadmin decodeMessageId: -i is declared optional but read unconditionally.
DecodeMessageIdCommond.buildCommandlineOptions marks -i/--messageId setRequired(false) (tools/.../command/message/DecodeMessageIdCommond.java:41-42) and execute() immediately does commandLine.getOptionValue('i').trim() (:50, outside the try), so running the command without -i throws a NullPointerException instead of reporting the missing argument.
Steps to Reproduce
mqadmin consumer -g myGroup -i 172.17.0.1@1234→Unrecognized option: -iplus the help text, exit code 1, althoughexecute()implements exactly this query.mqadmin resetMasterFlushOffset(or with only-b, or with only-o) →SubCommandException: ResetMasterFlushOffsetSubCommand command failedcaused byjava.lang.NullPointerException.mqadmin decodeMessageId→java.lang.NullPointerExceptionfromDecodeMessageIdCommond.execute.
At the unit level each case is reproduced by parsing the command's own option set with a plain DefaultParser (the pattern the module's existing tests use): the invocation either parses or it does not, and the missing-argument behavior is what the user sees before execute() runs.
What Did You Expect to See?
consumer -i <clientId>is accepted and performs the single-client query, like the siblingconsumerStatuscommand whose-i/--clientIdoption is declared.resetMasterFlushOffsetwithout-b/-oanddecodeMessageIdwithout-iare rejected by the parser with the standardMissing required option: -xmessage and the command's help, the way every othermqadmincommand whose arguments are mandatory behaves — instead of reachingexecute()and dying with aNullPointerExceptionstack trace.
What Did You See Instead?
Either an option the command actually reads is rejected as unknown, or a mandatory argument that is missing produces a raw NullPointerException / NumberFormatException with no usage hint. Both make the tool's own contract unreadable: mqadmin help <command> cannot even tell which arguments are mandatory, because they are declared optional.
Additional Context
Minimal fix: declare the missing option and mark the mandatory ones required —
ConsumerSubCommand: addnew Option("i", "clientId", true, "The consumer's client id")(optional, as inConsumerStatusSubCommand);ResetMasterFlushOffsetSubCommand:-b/--brokerAddrand-o/--offsetbecome required;DecodeMessageIdCommond:-i/--messageIdbecomes required.
Each command keeps its documented usage working (the flags are only made mandatory where execute() has no alternative path). I will open a PR with the changes plus tests that parse each command's own Options (asserting the missing-argument rejection and that the normal invocation still parses).
- 主要语言
- Java
- 星标
- 22.7k
- 派生
- 12k
- 平均合并
- 3 天 18 小时
- 30 天内合并 PR
- 17
环境准备
- 没有 Dockerfile 或 Docker Compose 文件
- 有 Pull Request 模板
- 阅读贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
apache/rocketmq 的其他 Issue
-
[Bug] RemotingHelper.connect swaps the socket send and receive buffer configuration可能已有人在做 @amalsaidov 今天认领。 未关闭
难度 2/5 1-3 小时 新手友好度 82/100
维护者通常 1 天内回复
-
CompressionType.of fails under the Turkish locale可能已有人在做 @sharanggupta 今天认领。 未关闭
难度 2/5 1-3 小时 新手友好度 83/100
维护者通常 1 天内回复
-
[rocketmq-client-python] TransactionMQProducer allocates an unused producer during initialization未关闭
难度 2/5 1-3 小时 新手友好度 82/100
维护者通常 1 天内回复
-
[Bug] notifyMasterOnline aborts the long-polling wake-up with a NullPointerException when an arrival drains a bucket first可能已有人在做 @iloveeyjafjalla 于 29 天前认领。 未关闭
难度 2/5 1-3 小时 新手友好度 82/100
apache/rocketmq#11441 · 1 条评论 ·
维护者通常 1 天内回复
-
[Enhancement] FilterFactory duplicate-registration and unregister semantics lack tests可能已有人在做 @chennaji9 于 34 天前认领。 未关闭
难度 2/5 1-3 小时 新手友好度 84/100
apache/rocketmq#11340 · 2 条评论 ·
维护者通常 1 天内回复
相似的 Issue
-
bug emitter:client:csharp
难度 2/5 1-3 小时 新手友好度 84/100
microsoft/typespec#12572 · 1 条评论 · 1 个 reaction ·
维护者通常 1 天内回复
-
GCC 15.2: -Wcast-qual warning - cast discards const qualifier from pointer target type (H5trace.c)未关闭
难度 2/5 1-3 小时 新手友好度 73/100
维护者通常 1 天内回复
-
needs-area-label
难度 2/5 1-3 小时 新手友好度 78/100
维护者通常 2 天内回复
-
area/ai area/backend component/zeebe kind/task
难度 2/5 1-3 小时 新手友好度 68/100
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 72/100
spAnser/reacharound#38 ·