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
- 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.
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
- 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
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
- Cannot activate BrowserController without an assigned browse
- This crawler instance is already running, you can add more r
- fetchNextRequest called on an uninitialized crawler
- The `response` property is not available. This might mean th
- The `gotoOptions` property is not available until `prepareNa
AI-assisted analysis of apify/crawlee@dbe57fb09c (2026-08-30).
Data as JSON: /api/errors/d66b899dc23fca6f.
Report an issue: GitHub.