Skip to content

fix(android): reject JS promise when plugin invoke fails with PluginLoadException or InvalidPluginMethodException - #8581

Open
xia-chao wants to merge 1 commit into
ionic-team:mainfrom
xia-chao:fix/android-invoke-error-rejects-js-promise
Open

xia-chao wants to merge 1 commit into
ionic-team:mainfrom
xia-chao:fix/android-invoke-error-rejects-js-promise

Conversation

@xia-chao

Copy link
Copy Markdown

Problem

When PluginHandle.invoke() throws PluginLoadException or InvalidPluginMethodException inside the taskHandler runnable in Bridge.callPluginMethod(), the catch block only calls Logger.error(...) and never calls call.errorCallback(...):

} catch (PluginLoadException | InvalidPluginMethodException ex) {
    Logger.error("Unable to execute plugin method", ex);
    // call.errorCallback() was never invoked
}

As a result, the JS-side promise returned by Capacitor.Plugins.*.method() never settles — the caller awaits forever with no error. A typical trigger is a typo'd method name on an existing plugin (e.g. await Plugins.App.getInfoTypo()), which throws InvalidPluginMethodException natively but leaves the JS promise pending forever.

The two neighboring error paths already reject the JS call:

  • plugin id not found → call.errorCallback(...) (Bridge.java ~L822)
  • outer catch (Exception ex)call.errorCallback(ex.toString()) (~L858)

Only the two invoke exceptions inside the runnable were missing the callback, so the promise hung instead of rejecting.

Fix

Call call.errorCallback(ex.getMessage()) in the PluginLoadException | InvalidPluginMethodException catch block, aligning it with the existing error paths. The error message now propagates to JS and the promise rejects.

Testing

Added BridgeCallPluginMethodTest (JUnit 4, Mockito) covering both exception types:

  • invalidPluginMethodCallsErrorCallback — plugin exists, method name is invalid → verifies errorCallback is invoked with a message containing the method name
  • pluginLoadExceptionCallsErrorCallback — plugin fails to load → verifies errorCallback is invoked with the load-failure message

Full unit suite passes (./gradlew -b capacitor/build.gradle testDebugUnitTest, 50/50, including the new tests).

// before fix: never settles
await Capacitor.Plugins.App.typoMethod(); // hangs forever

// after fix: rejects with the native error message
await Capacitor.Plugins.App.typoMethod(); // rejects: "No method typoMethod found for plugin com.example.App"

…oadException or InvalidPluginMethodException

When PluginHandle.invoke() throws PluginLoadException or
InvalidPluginMethodException inside the taskHandler runnable, only
Logger.error was called and call.errorCallback() was skipped, so the
JS-side promise never settled and awaited calls hung forever.

Align this path with the existing error paths (plugin not found, outer
catch) by calling call.errorCallback(ex.getMessage()).
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