{"record":{"id":"d66b899dc23fca6f","repo":"apify/crawlee","slug":"browsercontroller-already-has-a-browser-instance-a","errorCode":null,"errorMessage":"BrowserController already has a browser instance assigned.","messagePattern":"BrowserController already has a browser instance assigned\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/browser-pool/src/abstract-classes/browser-controller.ts","lineNumber":194,"sourceCode":"     * @ignore\n     */\n    activate(): void {\n        if (!this.browser) {\n            throw new Error('Cannot activate BrowserController without an assigned browser.');\n        }\n        this.#activate();\n        this.isActive = true;\n    }\n\n    /**\n     * @ignore\n     */\n    assignBrowser(\n        browser: LaunchResult,\n        launchContext: LaunchContext<Library, LibraryOptions, LaunchResult, NewPageOptions, NewPageResult>,\n    ): void {\n        if (this.browser) {\n            throw new Error('BrowserController already has a browser instance assigned.');\n        }\n        this.browser = browser;\n        this.launchContext = launchContext;\n        this.#commitBrowser();\n    }\n\n    /**\n     * Gracefully closes the browser and makes sure\n     * there will be no lingering browser processes.\n     *\n     * Emits 'browserClosed' event.\n     */\n    async close(): Promise<void> {\n        await this.#hasBrowserPromise;\n\n        try {\n            await this._close();\n            // TODO: shouldn't this go in a finally instead?","sourceCodeStart":176,"sourceCodeEnd":212,"githubUrl":"https://github.com/apify/crawlee/blob/dbe57fb09ca607ad59dcf998f3925ef9ac3bb26c/packages/browser-pool/src/abstract-classes/browser-controller.ts#L176-L212","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Create a fresh BrowserController for each new browser instead of reusing an assigned one.","Guard with `if (!controller.browser) controller.assignBrowser(...)` before assigning.","If the intent is to replace a browser, first retire/close the old controller and instantiate a new one."],"exampleFix":"// before\ncontroller.assignBrowser(newBrowser, ctx); // second call throws\n// after\nif (!controller.browser) {\n    controller.assignBrowser(newBrowser, ctx);\n} else {\n    controller = new PlaywrightBrowserController(options);\n    controller.assignBrowser(newBrowser, ctx);\n}","handlingStrategy":"validation","validationCode":"if (!controller.browser) controller.assignBrowser(browser, launchContext);","typeGuard":"function isUnassigned(c) { return c.browser === undefined || c.browser === null; }","tryCatchPattern":null,"preventionTips":["One controller per browser instance; never reuse assigned controllers","Create fresh controllers in retry/launch wrappers","In custom pool code, check controller.browser before assigning"],"tags":["lifecycle","browser-controller","api-misuse"],"backgroundTag":"browser-already-assigned","analyzedSha":"dbe57fb09ca607ad59dcf998f3925ef9ac3bb26c","analyzedAt":"2026-08-30T22:22:28.328Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}