apify/crawlee · error · Error

BrowserController already has a browser instance assigned.

Error message

BrowserController already has a browser instance assigned.

What it means

assignBrowser() enforces a one-to-one lifecycle: a BrowserController can only ever be bound to a single browser instance. The library throws this error when assignBrowser() is called on a controller whose `browser` field is already populated, preventing accidental reuse or double-assignment that would corrupt the controller's state.

Source

Thrown at packages/browser-pool/src/abstract-classes/browser-controller.ts:194

     * @ignore
     */
    activate(): void {
        if (!this.browser) {
            throw new Error('Cannot activate BrowserController without an assigned browser.');
        }
        this.#activate();
        this.isActive = true;
    }

    /**
     * @ignore
     */
    assignBrowser(
        browser: LaunchResult,
        launchContext: LaunchContext<Library, LibraryOptions, LaunchResult, NewPageOptions, NewPageResult>,
    ): void {
        if (this.browser) {
            throw new Error('BrowserController already has a browser instance assigned.');
        }
        this.browser = browser;
        this.launchContext = launchContext;
        this.#commitBrowser();
    }

    /**
     * Gracefully closes the browser and makes sure
     * there will be no lingering browser processes.
     *
     * Emits 'browserClosed' event.
     */
    async close(): Promise<void> {
        await this.#hasBrowserPromise;

        try {
            await this._close();
            // TODO: shouldn't this go in a finally instead?

View on GitHub (pinned to dbe57fb09c)

Solutions

  1. Create a fresh BrowserController for each new browser instead of reusing an assigned one.
  2. Guard with `if (!controller.browser) controller.assignBrowser(...)` before assigning.
  3. If the intent is to replace a browser, first retire/close the old controller and instantiate a new one.

Example fix

// before
controller.assignBrowser(newBrowser, ctx); // second call throws
// after
if (!controller.browser) {
    controller.assignBrowser(newBrowser, ctx);
} else {
    controller = new PlaywrightBrowserController(options);
    controller.assignBrowser(newBrowser, ctx);
}
Defensive patterns

Strategy: validation

Validate before calling

if (!controller.browser) controller.assignBrowser(browser, launchContext);

Type guard

function isUnassigned(c) { return c.browser === undefined || c.browser === null; }

Prevention

When it happens

Trigger: Calling controller.assignBrowser(browser, launchContext) twice on the same controller instance; reusing a controller from a retired/recycled browser to wrap a new browser; custom pool or plugin code that re-assigns controllers from a controller pool.

Common situations: Building custom pooling logic on top of BrowserPool; retrying launch code without creating a fresh controller; custom plugins that re-run assignBrowser on recycled controllers.

Related errors


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