apache/cordova-android · error · FileNotFoundException

Invalid plugin ID in URI: ${uri}

Error message

Invalid plugin ID in URI: ${uri}

What it means

When openForRead receives a URI of type PLUGIN (cdvplugin://...), CordovaResourceApi takes the URI host as the plugin id, looks it up via pluginManager.getPlugin(id), and throws FileNotFoundException if no plugin with that service name is registered. The host segment must equal the plugin's <name> (its serviceName), and the plugin must actually be initialized.

Source

Thrown at framework/src/org/apache/cordova/CordovaResourceApi.java:325

                conn.setDoInput(true);
                String mimeType = conn.getHeaderField("Content-Type");
                if (mimeType != null) {
                    mimeType = mimeType.split(";")[0];
                }
                int length = conn.getContentLength();
                InputStream inputStream;
                if ("gzip".equals(conn.getContentEncoding())) {
                    inputStream = new GZIPInputStream(conn.getInputStream());
                } else {
                    inputStream = conn.getInputStream();
                }
                return new OpenForReadResult(uri, inputStream, mimeType, length, null);
            }
            case URI_TYPE_PLUGIN: {
                String pluginId = uri.getHost();
                CordovaPlugin plugin = pluginManager.getPlugin(pluginId);
                if (plugin == null) {
                    throw new FileNotFoundException("Invalid plugin ID in URI: " + uri);
                }
                return plugin.handleOpenForRead(uri);
            }
        }
        throw new FileNotFoundException("URI not supported by CordovaResourceApi: " + uri);
    }

    public OutputStream openOutputStream(Uri uri) throws IOException {
        return openOutputStream(uri, false);
    }

    /**
     * Opens a stream to the given URI.
     *
     * @return Never returns null.
     * @throws IllegalArgumentException For relative URIs. Relative URIs should be resolved before
     *                                  being passed into this function.
     * @throws IOException              If the URI cannot be opened.

View on GitHub (pinned to 7c1e190064)

Solutions

  1. Make the URI authority exactly match the target plugin's <name> from plugin.xml — preferably build URIs with that plugin's toPluginUri()/PluginEntry rather than string concatenation
  2. Verify the plugin is actually loaded (check pluginInitialize ran / it appears in the plugin registry) before issuing reads of its URIs

Example fix

// before: hand-built URI with wrong plugin id
Uri u = Uri.parse("cdvplugin://my-plugin/foo");
resourceApi.openForRead(u);

// after: derive the URI from the plugin instance
Uri u = myPluginInstance.toPluginUri(origUri);
resourceApi.openForRead(u);
Defensive patterns

Strategy: type-guard

Validate before calling

// before openForRead on a plugin URI, verify the plugin is live
String pluginId = uri.getHost();
if (webView.getPluginManager().getPlugin(pluginId) == null) {
    throw new IllegalStateException("plugin not loaded: " + pluginId);
}

Type guard

static boolean isResolvablePluginUri(CordovaWebView webView, Uri uri) {
    return "cdvplugin".equals(uri.getScheme())
        && webView.getPluginManager().getPlugin(uri.getHost()) != null;
}

Try / catch

try {
    OpenForReadResult r = resourceApi.openForRead(uri);
} catch (FileNotFoundException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("Invalid plugin ID")) {
        // plugin missing/renamed: re-derive URI via toPluginUri() from the live plugin
    }
}

Prevention

When it happens

Trigger: Calling openForRead on a cdvplugin:// URI whose authority is not a loaded plugin: wrong/renamed <name> in plugin.xml (serviceName is derived from it), plugin removed/failed to initialize, URI hand-built with a mistyped authority, or plugin URIs constructed while the plugin has not finished initializing.

Common situations: Plugin renamed between versions so persisted cdvplugin:// URLs (cached in the WebView, localStorage, database blobs) no longer resolve; a plugin disabled at runtime; inter-plugin code guessing another plugin's service name.

Related errors


AI-assisted analysis of apache/cordova-android@7c1e190064 (2026-08-22). Data as JSON: /api/errors/7830051efa101c48. Report an issue: GitHub.