Skip to content

fix(kord): don't NPE when publishing commands that take arguments - #112

Open
NightmarePog wants to merge 1 commit into
Incendo:masterfrom
NightmarePog:fix/kord-npe-root-command
Open

fix(kord): don't NPE when publishing commands that take arguments#112
NightmarePog wants to merge 1 commit into
Incendo:masterfrom
NightmarePog:fix/kord-npe-root-command

Conversation

@NightmarePog

Copy link
Copy Markdown

Registering any command whose root literal isn't executable on its own kills the publish:

java.lang.NullPointerException: Cannot invoke "org.incendo.cloud.Command.senderType()" because the return value of "org.incendo.cloud.internal.CommandNode.command()" is null
	at org.incendo.cloud.discord.kord.StandardKordCommandFactory.createCommands(StandardKordCommandFactory.kt:128)
	at org.incendo.cloud.discord.kord.StandardKordCommandFactory.createGlobalCommands(StandardKordCommandFactory.kt:99)
	at org.incendo.cloud.discord.kord.KordEventListener.listen(KordEventListener.kt:79)

CommandNode#command() is @MonotonicNonNull and only gets populated on nodes that terminate a command, so a root literal carries one only when the whole command is that literal and nothing else. /ping is fine; /warn <user> or a command with subcommands is not. Kotlin sees the getter as a platform type, so nothing complains at compile time and the first createGlobalCommands call takes the bot's command registration down with it.

The same permission lookup landed in jda5 in #60 with a rootNode.command() != null guard around it (still there in cloud-jda6). kord's copy never got one. This ports it over.

Reproduced and verified against 1.0.0-beta.4 in a bot with /warn <user>, /clear-chat <amount> and a couple of subcommand groups. Before: publish dies on the first one. After: everything registers.

about the test

There was no test source set for cloud-kord, so I added one. To reach createCommands I had to widen it from private to internal — everything above it wants a live Kord, and MultiApplicationCommandBuilder's concrete subclasses are constructible on their own, so this was the cheapest seam. The class itself is already internal, so no public API moves. Say the word if you'd rather I drop the test and the visibility bump and keep this to the two-line fix.

testCreateCommandWithArgument fails with the NPE above on master and passes with the fix; testCreateCommandWithoutArgument passes either way.

what this doesn't fix

Commands that take arguments still won't get a default member permission applied, since there's no root command to read a sender type from. I think that's what #91 is about. Resolving it properly means deciding which descendant's sender type a root should answer with, which felt like a different PR.

CommandNode#command() is only set on nodes that terminate a command, so a
root literal has one only when the command is just that literal. Publishing
/foo <bar>, or anything with subcommands, blew up in
StandardKordCommandFactory while reading the sender type for the default
member permission lookup.

jda5 got a null check for this in Incendo#60, kord's copy of the same code didn't.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant