tauri-apps/tauri · error · InvalidCommandException
No command found for plugin
Error message
No command ${invoke.command} found for plugin ${instance.javaClass.name} What it means
`PluginHandle.invoke` looks up the requested command among methods indexed from the plugin instance. If no `@Command`-annotated (or otherwise registered) method matches `invoke.command`, it throws `InvalidCommandException` with this message naming the missing command and plugin class.
Solutions
- Verify the command name in the invoke string matches exactly (case-sensitive) an `@Command`-annotated public method on the plugin class.
- Add the missing `@Command` annotation or register the method, then rebuild the Android app (Gradle clean/build).
- Sync the mobile plugin version with the JS/npm bindings package.
- Check `PluginManager.registerPlugin` is passed the correct plugin class and the plugin name in the invoke matches the registered name.
Example fix
// before
class EchoPlugin : Plugin() { fun echo(invoke: Invoke) { ... } } // no annotation
// after
class EchoPlugin : Plugin() {
@Command
fun echo(invoke: Invoke) { ... }
} Defensive patterns
Strategy: validation
Validate before calling
// Frontend: verify command exists against generated bindings
import { echo } from './bindings/myplugin'; // typed bindings fail at compile time on typos
echo(args); Type guard
const knownCommands = new Set(['echo', 'watch']); const isValidCommand = (c) => knownCommands.has(c);
Try / catch
// Kotlin side
try {
pluginHandle.invoke(invoke)
} catch (e: InvalidCommandException) {
invoke.reject(e.message)
} Prevention
- Annotate every public plugin method with @Command
- Use generated typed bindings instead of raw invoke strings
- Rebuild the Android app after changing plugin commands
When it happens
Trigger: JS/Rust calls `invoke('plugin:<name>|<command>', ...)` where `<command>` has no matching annotated method on the Android plugin class — typo, wrong plugin name, or command removed/renamed in a plugin update.
Common situations: Plugin method missing the `@Command` annotation; frontend bindings generated from a newer plugin version than the native side; method not public so `indexMethods` skipped it.
Related errors
- Not all items are instances of the given type
- the plugin manager has no activity to launch from
- unexpected channel value $channelDef
- Android folder already exists
- Android NDK invalid. Make sure the NDK_HOME environment…
AI-assisted analysis of tauri-apps/tauri@460ec35447 (2026-09-18).
Data as JSON: /api/errors/2d8a7c4b95c17ca8.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tauri/mobile/android/src/main/java/app/tauri/plugin/PluginHandle.kt:150
"""
$perm
""".trimIndent()
)
}
invoke.reject(builder.toString())
return false
}
return true
}
@Throws(
InvalidCommandException::class,
IllegalAccessException::class
)
fun invoke(invoke: Invoke) {
val methodMeta = commands[invoke.command]
?: throw InvalidCommandException("No command " + invoke.command + " found for plugin " + instance.javaClass.name)
methodMeta.method.invoke(instance, invoke)
}
private fun indexMethods() {
val methods = mutableListOf<Method>()
var pluginCursor: Class<*> = instance.javaClass
while (pluginCursor.name != Any::class.java.name) {
methods.addAll(listOf(*pluginCursor.declaredMethods))
pluginCursor = pluginCursor.superclass
}
for (method in methods) {
if (method.isAnnotationPresent(Command::class.java)) {
val command = method.getAnnotation(Command::class.java) ?: continue
val methodMeta = CommandData(method, command)
commands[method.name] = methodMeta
}
View on GitHub (pinned to 460ec35447)