apify/crawlee · error
Could not resolve StagehandController for page — is the brow
Error message
Could not resolve StagehandController for page — is the browser pool configured correctly?
What it means
setUpStagehand() maps a crawling context's page back to its StagehandController via getBrowserControllerByPage() to fetch the Stagehand instance. When no controller is registered for that page, the crawler cannot proceed and throws this error hinting at a browser pool misconfiguration.
Source
Thrown at packages/stagehand-crawler/src/internals/stagehand-crawler.ts:520
this.browserPool as unknown as {
getBrowserControllerByPage(page: StagehandPage): StagehandController | undefined;
}
).getBrowserControllerByPage(page);
}
return undefined;
}
/**
* Enhance the page with Stagehand AI methods.
*/
private async setUpStagehand(crawlingContext: {
page: Page;
}): Promise<{ stagehand: Stagehand; page: StagehandPage }> {
const controller = this.getBrowserControllerByPage(crawlingContext.page as StagehandPage);
if (!controller) {
throw new Error(
'Could not resolve StagehandController for page — is the browser pool configured correctly?',
);
}
const stagehand = controller.getStagehand();
return {
stagehand,
page: enhancePageWithStagehand(crawlingContext.page, stagehand),
};
}
/**
* Navigation handler for Stagehand crawler.
* Uses standard Playwright navigation.
*/
protected override async navigationHandler(
crawlingContext: StagehandCrawlingContext,View on GitHub (pinned to dbe57fb09c)
Solutions
- Ensure the browser pool uses StagehandPlugin so pages get a StagehandController
- Create all pages through the crawler/browser pool, never manually via playwright.chromium.launch()
- Confirm you call enhancedPage helpers only on pages the same StagehandCrawler instance created
- If using a custom page-generating plugin, wrap it so it delegates registration to StagehandController
Example fix
// before
browserPoolOptions: { browserPlugins: [new PlaywrightPlugin(chromium.launchOptions)] }
// after
browserPoolOptions: { browserPlugins: [new StagehandPlugin()] } Defensive patterns
Strategy: validation
Validate before calling
const controller = crawler.getBrowserControllerByPage(page);
if (!controller) {
throw new Error('page is not managed by the Stagehand browser pool; aborting stagehand setup');
} Type guard
const isPoolPage = (crawler, page) =>
typeof crawler.getBrowserControllerByPage === 'function' &&
crawler.getBrowserControllerByPage(page) != null; Try / catch
try {
const { stagehand, page: spage } = await crawler.setUpStagehand(ctx);
} catch (err) {
if (err.message.includes('Could not resolve StagehandController')) {
throw new Error('Configure browserPoolOptions.browserPlugins with StagehandPlugin');
}
throw err;
} Prevention
- Only create pages through the crawler's browser pool
- Use StagehandPlugin, not generic Playwright/Puppeteer plugins
- Never mix pages from different crawler instances
- Assert the pool configuration in an integration test
When it happens
Trigger: Using a page inside requestHandler that did not originate from the Stagehand browser pool — e.g. a page created manually via playwright, pages created before the plugin registered controllers, or mixing StagehandCrawler with a custom browserPoolOptions browser plugin (default Playwright/Puppeteer plugin).
Common situations: Configuring browserPoolOptions with plain chromiumLauncherPlugin instead of StagehandPlugin, running pages through a different crawler instance, or passing foreign page objects to enhanced page utilities.
Related errors
- Stagehand instance not found for browser
- ${crawlerName}: ${names.map((name) => `\`${name}\``).join(',
- Provided browserPlugin is not one of the plugins used by Bro
- Remote browser endpoint resolved to an empty string.
- Remote browser endpoint() must return a URL string or an obj
AI-assisted analysis of apify/crawlee@dbe57fb09c (2026-08-30).
Data as JSON: /api/errors/80773f9876d36bab.
Report an issue: GitHub.