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

  1. Verify the command name in the invoke string matches exactly (case-sensitive) an `@Command`-annotated public method on the plugin class.
  2. Add the missing `@Command` annotation or register the method, then rebuild the Android app (Gradle clean/build).
  3. Sync the mobile plugin version with the JS/npm bindings package.
  4. 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

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


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)