apache/cordova-android · critical · RuntimeException
Failed to create webview.
Error message
Failed to create webview.
What it means
Cordova instantiates its WebView engine reflectively. CordovaWebViewImpl.createEngine reads the <preference name="webview"> value from config.xml (default: org.apache.cordova.engine.SystemWebViewEngine), loads that class with Class.forName, and calls its (Context, CordovaPreferences) constructor. Any failure in that chain — ClassNotFoundException (bad class name / plugin not on classpath), NoSuchMethodException (missing 2-arg constructor), ClassCastException, or an exception thrown inside the engine's own constructor — is rethrown wrapped in this RuntimeException.
Source
Thrown at framework/src/org/apache/cordova/CordovaWebViewImpl.java:84
private boolean hasPausedEver;
// The URL passed to loadUrl(), not necessarily the URL of the current page.
String loadedUrl;
/** custom view created by the browser (a video player for example) */
private View mCustomView;
private WebChromeClient.CustomViewCallback mCustomViewCallback;
private Set<Integer> boundKeyCodes = new HashSet<Integer>();
public static CordovaWebViewEngine createEngine(Context context, CordovaPreferences preferences) {
String className = preferences.getString("webview", SystemWebViewEngine.class.getCanonicalName());
try {
Class<?> webViewClass = Class.forName(className);
Constructor<?> constructor = webViewClass.getConstructor(Context.class, CordovaPreferences.class);
return (CordovaWebViewEngine) constructor.newInstance(context, preferences);
} catch (Exception e) {
throw new RuntimeException("Failed to create webview. ", e);
}
}
public CordovaWebViewImpl(CordovaWebViewEngine cordovaWebViewEngine) {
this.engine = cordovaWebViewEngine;
}
// Convenience method for when creating programmatically (not from Config.xml).
public void init(CordovaInterface cordova) {
init(cordova, new ArrayList<PluginEntry>(), new CordovaPreferences());
}
@SuppressLint("Assert")
@Override
public void init(CordovaInterface cordova, List<PluginEntry> pluginEntries, CordovaPreferences preferences) {
if (this.cordova != null) {
throw new IllegalStateException();
}View on GitHub (pinned to 7c1e190064)
Solutions
- Read the wrapped cause in the stack trace: ClassNotFoundException means the class name/plugin is wrong; InvocationTargetException means the engine's constructor threw — fix whatever its cause says.
- If you do not need a custom engine, delete the <preference name="webview" .../> line from config.xml so the default SystemWebViewEngine is used, then cordova prepare android.
- If you do need it, reinstall the engine plugin (cordova plugin ls / cordova plugin add <engine-plugin>) and verify the preference value exactly matches the engine class's fully-qualified name.
- For a custom engine, make the class public, implement CordovaWebViewEngine, and expose a public (Context, CordovaPreferences) constructor.
- For minified release builds, add a ProGuard/R8 keep rule for the engine class and its constructor.
Example fix
// before — config.xml references an engine whose plugin was removed <preference name="webview" value="com.example.FastWebViewEngine" /> // after — option A: drop the preference and use the built-in engine <!-- default SystemWebViewEngine is used --> // after — option B: restore the class via its plugin // cordova plugin add cordova-plugin-fast-webview <preference name="webview" value="com.example.FastWebViewEngine" />
Defensive patterns
Strategy: try-catch
Validate before calling
// Verify the configured engine class loads before creating the engine
String engineClass = preferences.getString("webview", SystemWebViewEngine.class.getCanonicalName());
try {
Class<?> cls = Class.forName(engineClass); // fails fast with a clear ClassNotFoundException
cls.getConstructor(Context.class, CordovaPreferences.class); // constructor present?
} catch (ReflectiveOperationException e) {
throw new IllegalStateException("Webview engine class " + engineClass + " is not usable; check the <preference name=\"webview\"/> and the engine plugin install", e);
} Try / catch
try {
engine = CordovaWebViewImpl.createEngine(context, preferences);
} catch (RuntimeException e) {
Throwable cause = e.getCause() != null ? e.getCause() : e;
if (cause instanceof ClassNotFoundException) {
// bad <preference name="webview"> value or engine plugin missing — fix config.xml / reinstall plugin
} else if (cause instanceof NoSuchMethodException) {
// engine lacks the required (Context, CordovaPreferences) constructor
} else {
// engine constructor threw; inspect cause for the real failure
}
throw new IllegalStateException("Webview engine failed to initialize", cause);
} Prevention
- Add or remove the webview preference and its engine plugin together — never leave the preference pointing at an uninstalled class.
- Keep custom engine classes public with a (Context, CordovaPreferences) constructor.
- Add R8/ProGuard keep rules for reflectively-loaded engine classes before shipping release builds.
- Run one debug build after any config.xml change that touches the webview preference.
When it happens
Trigger: config.xml contains <preference name="webview" value="com.example.MyEngine"/> but the engine plugin providing that class was removed or never installed; the FQN has a typo; a custom engine class lacks a public constructor taking (Context, CordovaPreferences); the engine's constructor itself throws (missing dependency, unsupported Android version); R8/ProGuard strips or renames the engine class in a release build.
Common situations: A custom webview engine plugin (e.g. a Crosswalk-style or vendor WebView engine) is uninstalled while its config.xml preference remains; projects migrated between cordova-android majors carry stale preferences; engine plugin installed but incompatible with the current platform release; release builds obfuscating the reflectively-loaded class.
Related errors
- Failed to install apk to target: ${output}
- One of the following attributes are set but missing the othe
- Unsupported keycode: ${keyCode}
- ${filePath}: Missing key required "${key}"
- Expected Android Build Tools version >= ${cordovaConfig.MIN_
AI-assisted analysis of apache/cordova-android@7c1e190064 (2026-08-22).
Data as JSON: /api/errors/09d8efac63683b88.
Report an issue: GitHub.