diff --git a/api/src/main/java/com/velocitypowered/api/command/BrigadierCommand.java b/api/src/main/java/com/velocitypowered/api/command/BrigadierCommand.java
index da40f48a5..67af56634 100644
--- a/api/src/main/java/com/velocitypowered/api/command/BrigadierCommand.java
+++ b/api/src/main/java/com/velocitypowered/api/command/BrigadierCommand.java
@@ -18,7 +18,7 @@ import com.mojang.brigadier.tree.LiteralCommandNode;
public final class BrigadierCommand implements Command {
/**
- * Return code used by a {@link com.mojang.brigadier.Command} to indicate
+ * The return code used by a {@link com.mojang.brigadier.Command} to indicate
* the command execution should be forwarded to the backend server.
*/
public static final int FORWARD = 0xF6287429;
diff --git a/api/src/main/java/com/velocitypowered/api/command/Command.java b/api/src/main/java/com/velocitypowered/api/command/Command.java
index 68f4594e4..60e713873 100644
--- a/api/src/main/java/com/velocitypowered/api/command/Command.java
+++ b/api/src/main/java/com/velocitypowered/api/command/Command.java
@@ -13,8 +13,8 @@ import com.velocitypowered.api.proxy.connection.Player;
* Represents a command that can be executed by a {@link CommandSource}
* such as a {@link Player} or the console.
*
- *
You should not subclass Command
. Use one of the following
- * subinterfaces:
+ * You must not subclass Command
. Use one of the following
+ * registrable subinterfaces:
*
*
* - {@link BrigadierCommand} wraps a Brigadier literal command node. It supports parameterized
diff --git a/api/src/main/java/com/velocitypowered/api/command/CommandManager.java b/api/src/main/java/com/velocitypowered/api/command/CommandManager.java
index 144d3e579..17baf508f 100644
--- a/api/src/main/java/com/velocitypowered/api/command/CommandManager.java
+++ b/api/src/main/java/com/velocitypowered/api/command/CommandManager.java
@@ -39,7 +39,9 @@ public interface CommandManager {
* @param alias the first command alias
* @param command the command to register
* @param otherAliases additional aliases
- * @throws IllegalArgumentException if one of the given aliases is already registered
+ * @throws IllegalArgumentException if one of the given aliases is already registered, or
+ * the given command does not implement a registrable {@link Command} subinterface
+ * @see Command for a list of registrable {@link Command} subinterfaces
*/
default void register(String alias, Command command, String... otherAliases) {
register(createMetaBuilder(alias).aliases(otherAliases).build(), command);
@@ -58,7 +60,9 @@ public interface CommandManager {
*
* @param meta the command metadata
* @param command the command to register
- * @throws IllegalArgumentException if one of the given aliases is already registered
+ * @throws IllegalArgumentException if one of the given aliases is already registered, or
+ * the given command does not implement a registrable {@link Command} subinterface
+ * @see Command for a list of registrable {@link Command} subinterfaces
*/
void register(CommandMeta meta, Command command);
diff --git a/api/src/main/java/com/velocitypowered/api/command/CommandMeta.java b/api/src/main/java/com/velocitypowered/api/command/CommandMeta.java
index 60f933c0b..14aff141b 100644
--- a/api/src/main/java/com/velocitypowered/api/command/CommandMeta.java
+++ b/api/src/main/java/com/velocitypowered/api/command/CommandMeta.java
@@ -24,8 +24,8 @@ public interface CommandMeta {
Collection aliases();
/**
- * Returns a collection containing command nodes that provide additional
- * argument metadata and tab-complete suggestions.
+ * Returns an immutable collection containing command nodes that provide
+ * additional argument metadata and tab-complete suggestions.
* Note some {@link Command} implementations may not support hinting.
*
* @return the hinting command nodes
@@ -51,6 +51,8 @@ public interface CommandMeta {
*
* @param node the command node
* @return this builder, for chaining
+ * @throws IllegalArgumentException if the node is executable, i.e. has a non-null
+ * {@link com.mojang.brigadier.Command}, or has a redirect.
*/
Builder hint(CommandNode node);
diff --git a/api/src/main/java/com/velocitypowered/api/command/ConsoleCommandSource.java b/api/src/main/java/com/velocitypowered/api/command/ConsoleCommandSource.java
index 3a369ca45..c9b7f8753 100644
--- a/api/src/main/java/com/velocitypowered/api/command/ConsoleCommandSource.java
+++ b/api/src/main/java/com/velocitypowered/api/command/ConsoleCommandSource.java
@@ -7,8 +7,6 @@
package com.velocitypowered.api.command;
-import com.velocitypowered.api.command.CommandSource;
-
/**
* Indicates that the executor of the command is the console.
*/
diff --git a/api/src/main/java/com/velocitypowered/api/command/InvocableCommand.java b/api/src/main/java/com/velocitypowered/api/command/InvocableCommand.java
index e6183e52d..b5301ae3b 100644
--- a/api/src/main/java/com/velocitypowered/api/command/InvocableCommand.java
+++ b/api/src/main/java/com/velocitypowered/api/command/InvocableCommand.java
@@ -14,6 +14,11 @@ import java.util.concurrent.CompletableFuture;
/**
* A command that can be executed with arbitrary arguments.
*
+ *
Modifying the command tree (e.g. registering a command via
+ * {@link CommandManager#register(CommandMeta, Command)}) during
+ * permission checking and suggestions provision results in
+ * undefined behavior, which may include deadlocks.
+ *
* @param the type of the command invocation object
*/
public interface InvocableCommand> extends Command {