{"record":{"id":"3f7c46b11440671a","repo":"apify/crawlee","slug":"cannot-activate-browsercontroller-without-an-assig","errorCode":null,"errorMessage":"Cannot activate BrowserController without an assigned browser.","messagePattern":"Cannot activate BrowserController without an assigned browser\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/browser-pool/src/abstract-classes/browser-controller.ts","lineNumber":180,"sourceCode":"    #hasBrowserPromise = new Promise<void>((resolve) => {\n        this.#commitBrowser = resolve;\n    });\n\n    constructor(browserPlugin: BrowserPlugin<Library, LibraryOptions, LaunchResult, NewPageOptions, NewPageResult>) {\n        super();\n        this.log = serviceLocator.getLogger().child({ prefix: 'BrowserPool' });\n        this.browserPlugin = browserPlugin;\n    }\n\n    /**\n     * Activates the BrowserController. If you try to open new pages before\n     * activation, the pages will get queued and will only be opened after\n     * activate is called.\n     * @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();","sourceCodeStart":162,"sourceCodeEnd":198,"githubUrl":"https://github.com/apify/crawlee/blob/dbe57fb09ca607ad59dcf998f3925ef9ac3bb26c/packages/browser-pool/src/abstract-classes/browser-controller.ts#L162-L198","documentation":"BrowserController.activate() is the entry point that marks a controller as active after a browser has been attached. The library throws this error when activate() is called while the internal `this.browser` field is still unset, because there is nothing to activate. It is a lifecycle-order guard: the controller must first have a browser assigned (via assignBrowser) before activation makes sense.","triggerScenarios":"Calling browserController.activate() directly (it is public despite the @ignore tag) on a freshly constructed controller, or on a controller that was never assigned a LaunchResult — e.g. instantiating a controller subclass manually instead of going through BrowserPool.newPage()/newPageInNewBrowser().","commonSituations":"Developers subclassing BrowserController and managing the lifecycle by hand; calling internal-ish methods out of order; plugins with custom _launch logic that never commit a browser before activation; version changes where activation used to implicitly launch.","solutions":["Do not call activate() yourself — use BrowserPool.newPage() or newPageInNewBrowser() which handle assignment and activation in the correct order.","If you must manage the controller manually, call controller.assignBrowser(launchResult, launchContext) before activate().","Check that your custom plugin's _launch implementation actually returns/commits a browser so assignBrowser is reached."],"exampleFix":"// before\nconst controller = new PlaywrightBrowserController(options);\ncontroller.activate(); // throws\n// after\nconst controller = new PlaywrightBrowserController(options);\ncontroller.assignBrowser(await playwright.launch(), launchContext);\ncontroller.activate();","handlingStrategy":"validation","validationCode":"function canActivate(controller) { return controller.browser != null && !controller.isActive; }\nif (!canActivate(controller)) throw new Error('assign a browser before activate()');","typeGuard":"function hasBrowser(c) { return c.browser !== undefined && c.browser !== null; }","tryCatchPattern":null,"preventionTips":["Never call activate() directly; go through BrowserPool.newPage()/newPageInNewBrowser()","Always pair manual controller use with assignBrowser() first","Keep lifecycle order: construct -> assignBrowser -> activate"],"tags":["lifecycle","browser-controller","api-misuse"],"backgroundTag":"browser-not-assigned","analyzedSha":"dbe57fb09ca607ad59dcf998f3925ef9ac3bb26c","analyzedAt":"2026-08-30T22:22:28.328Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}