[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)

Aperta
#11,410 1 commento 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 1 giorno

@iloveeyjafjalla ci sta già lavorando.

Dal 13/10/2026.

  • #11411 di @iloveeyjafjalla — aperta

Valutazione

Difficoltà
2/5
Tempo stimato
Mezza giornata
Idoneità per principianti
25/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Attiva
Stack tecnologico
java
Ambito
cli

Direzione di ricerca

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.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

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
  1. mqadmin consumer -g myGroup -i 172.17.0.1@1234 → Unrecognized option: -i plus the help text, exit code 1, although execute() implements exactly this query.
  2. mqadmin resetMasterFlushOffset (or with only -b, or with only -o) → SubCommandException: ResetMasterFlushOffsetSubCommand command failed caused by java.lang.NullPointerException.
  3. mqadmin decodeMessageId → java.lang.NullPointerException from DecodeMessageIdCommond.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 sibling consumerStatus command whose -i/--clientId option is declared.
  • resetMasterFlushOffset without -b/-o and decodeMessageId without -i are rejected by the parser with the standard Missing required option: -x message and the command's help, the way every other mqadmin command whose arguments are mandatory behaves — instead of reaching execute() and dying with a NullPointerException stack 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: add new Option("i", "clientId", true, "The consumer's client id") (optional, as in ConsumerStatusSubCommand);
  • ResetMasterFlushOffsetSubCommand: -b/--brokerAddr and -o/--offset become required;
  • DecodeMessageIdCommond: -i/--messageId becomes 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).

Lingua principale
Java
Stelle
22.7k
Fork
12k
Merge medio
3g 18h
PR unite (30g)
17

Preparare l'ambiente

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di apache/rocketmq

Tutte le issue di apache/rocketmq

Issue simili

Altre issue su Java

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.