apify/crawlee · error · Error

Browser plugin at index ${i} (${providedPluginName}) is not

Error message

Browser plugin at index ${i} (${providedPluginName}) is not an instance of the same plugin as the first plugin provided (${firstPluginName}).

What it means

BrowserPool can manage multiple browser plugins, but all plugins passed to the constructor must derive from the same plugin class so the pool can rely on a consistent internal interface (BrowserPlugins type). The constructor throws this plain Error when a plugin at index i fails the `instanceof` check against the constructor of the first plugin.

Source

Thrown at packages/browser-pool/src/browser-pool.ts:397

            postLaunchHooks,
            prePageCreateHooks,
            postPageCreateHooks,
            prePageCloseHooks,
            postPageCloseHooks,
            useFingerprints,
            fingerprintOptions,
        } = parseArgument(options, browserPoolOptionsSchema);

        const firstPluginConstructor = browserPlugins[0].constructor as typeof BrowserPlugin;

        for (let i = 1; i < browserPlugins.length; i++) {
            const providedPlugin = browserPlugins[i];

            if (!(providedPlugin instanceof firstPluginConstructor)) {
                const firstPluginName = firstPluginConstructor.name;
                const providedPluginName = (providedPlugin as BrowserPlugin).constructor.name;

                throw new Error(
                    `Browser plugin at index ${i} (${providedPluginName}) is not an instance of the same plugin as the first plugin provided (${firstPluginName}).`,
                );
            }
        }

        this.browserPlugins = browserPlugins as unknown as BrowserPlugins;
        this.maxOpenPagesPerBrowser = maxOpenPagesPerBrowser;
        this.maxOpenBrowsers = Infinity;
        this.retireBrowserAfterPageCount = retireBrowserAfterPageCount;
        this.operationTimeoutMillis = operationTimeoutSecs * 1000;
        this.closeInactiveBrowserAfterMillis = closeInactiveBrowserAfterSecs * 1000;
        this.useFingerprints = useFingerprints;
        this.fingerprintOptions = fingerprintOptions;

        this.#browserRetireInterval = setInterval(
            async () =>
                this.activeBrowserControllers.forEach((controller) => {
                    if (

View on GitHub (pinned to dbe57fb09c)

Solutions

  1. Pass only plugins of the same class/family to browserPlugins.
  2. Use multiple BrowserPools if you need both Playwright and Puppeteer.
  3. Deduplicate node_modules so a single plugin package version is installed (check `npm ls`).

Example fix

// before
new BrowserPool({ browserPlugins: [new PlaywrightPlugin(), new PuppeteerPlugin()] });
// after
new BrowserPool({ browserPlugins: [new PlaywrightPlugin(), new PlaywrightPlugin()] });
// or one pool per family:
const pwPool = new BrowserPool({ browserPlugins: [new PlaywrightPlugin()] });
const ppPool = new BrowserPool({ browserPlugins: [new PuppeteerPlugin()] });
Defensive patterns

Strategy: validation

Validate before calling

const plugins = [new PlaywrightPlugin(), new PlaywrightPlugin()];
if (new Set(plugins.map(p => p.constructor)).size !== 1) throw new Error('all plugins must be the same class');
const pool = new BrowserPool({ browserPlugins: plugins });

Type guard

function samePluginFamily(plugins) { return plugins.every(p => p instanceof plugins[0].constructor); }

Prevention

When it happens

Trigger: new BrowserPool({ browserPlugins: [new PlaywrightPlugin(), new PuppeteerPlugin()] }) — mixing plugins of different families; passing a similarly-named plugin from a different package/version so instanceof fails.

Common situations: Migrating between crawlee/playwright/puppeteer plugin packages; duplicated plugin versions in node_modules (instanceof fails across duplicate copies); accidentally mixing Playwright and Puppeteer plugins in one pool.

Related errors


AI-assisted analysis of apify/crawlee@dbe57fb09c (2026-08-30). Data as JSON: /api/errors/5f79201b54a8d8f0. Report an issue: GitHub.