{"record":{"id":"2d8a7c4b95c17ca8","repo":"tauri-apps/tauri","slug":"no-command-invoke-command-found-for-plugin-instance","errorCode":null,"errorMessage":"No command ${invoke.command} found for plugin ${instance.javaClass.name}","messagePattern":"No command (.+?) found for plugin (.+?)","errorType":"exception","errorClass":"InvalidCommandException","httpStatus":null,"severity":"error","filePath":"crates/tauri/mobile/android/src/main/java/app/tauri/plugin/PluginHandle.kt","lineNumber":150,"sourceCode":"          \"\"\"\n                $perm\n\n                \"\"\".trimIndent()\n        )\n      }\n      invoke.reject(builder.toString())\n      return false\n    }\n    return true\n  }\n\n  @Throws(\n    InvalidCommandException::class,\n    IllegalAccessException::class\n  )\n  fun invoke(invoke: Invoke) {\n    val methodMeta = commands[invoke.command]\n      ?: throw InvalidCommandException(\"No command \" + invoke.command + \" found for plugin \" + instance.javaClass.name)\n    methodMeta.method.invoke(instance, invoke)\n  }\n\n  private fun indexMethods() {\n    val methods = mutableListOf<Method>()\n    var pluginCursor: Class<*> = instance.javaClass\n    while (pluginCursor.name != Any::class.java.name) {\n      methods.addAll(listOf(*pluginCursor.declaredMethods))\n      pluginCursor = pluginCursor.superclass\n    }\n\n    for (method in methods) {\n      if (method.isAnnotationPresent(Command::class.java)) {\n        val command = method.getAnnotation(Command::class.java) ?: continue\n        val methodMeta = CommandData(method, command)\n        commands[method.name] = methodMeta\n      }\n","sourceCodeStart":132,"sourceCodeEnd":168,"githubUrl":"https://github.com/tauri-apps/tauri/blob/460ec35447493200d64290dd7f015d5a91d0fd58/crates/tauri/mobile/android/src/main/java/app/tauri/plugin/PluginHandle.kt#L132-L168","documentation":"`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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nclass EchoPlugin : Plugin() { fun echo(invoke: Invoke) { ... } } // no annotation\n// after\nclass EchoPlugin : Plugin() {\n  @Command\n  fun echo(invoke: Invoke) { ... }\n}","handlingStrategy":"validation","validationCode":"// Frontend: verify command exists against generated bindings\nimport { echo } from './bindings/myplugin'; // typed bindings fail at compile time on typos\necho(args);","typeGuard":"const knownCommands = new Set(['echo', 'watch']);\nconst isValidCommand = (c) => knownCommands.has(c);","tryCatchPattern":"// Kotlin side\ntry {\n  pluginHandle.invoke(invoke)\n} catch (e: InvalidCommandException) {\n  invoke.reject(e.message)\n}","preventionTips":["Annotate every public plugin method with @Command","Use generated typed bindings instead of raw invoke strings","Rebuild the Android app after changing plugin commands"],"tags":["android","kotlin","plugin","ipc","command-not-found"],"backgroundTag":"command-not-found","analyzedSha":"460ec35447493200d64290dd7f015d5a91d0fd58","analyzedAt":"2026-09-18T23:55:51.277Z","contentChangedAt":"2026-09-18T23:55:51.277Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}