apify/crawlee · error
Stagehand did not register the page within ${timeoutMs}ms
Error message
Stagehand did not register the page within ${timeoutMs}ms What it means
After creating a page, StagehandCrawler polls until Stagehand registers the page (keyed by main frame id) in its internal registry. If registration does not happen within timeoutMs, this error is thrown. As the source comment states, Stagehand skips registration entirely when it cannot install its helper script into the page's CDP session — so waiting longer will never help; it can never resolve.
Source
Thrown at packages/stagehand-crawler/src/internals/stagehand-controller.ts:104
* a short window, and the AI methods fail with 'Failed to resolve V3 Page from Playwright page'.
* Stagehand's own `newPage()` polls for the same reason.
*/
private async waitForStagehandToRegisterPage(page: Page, timeoutMs = 10_000): Promise<void> {
const stagehand = this.getStagehand();
const mainFrameId = await this.getMainFrameId(page);
const deadline = Date.now() + timeoutMs;
while (Date.now() < deadline) {
if (stagehand.context.resolvePageByMainFrameId(mainFrameId)) {
return;
}
await sleep(25);
}
// Stagehand skips registration entirely when it cannot install its helper script into the page's CDP
// session, so this is not always just a slow attach - it can never resolve.
throw new Error(`Stagehand did not register the page within ${timeoutMs}ms`);
}
/**
* Reads the page's main frame id, which is the key Stagehand resolves pages by.
*/
private async getMainFrameId(page: Page): Promise<string> {
const cdpSession = await page.context().newCDPSession(page);
try {
const { frameTree } = await cdpSession.send('Page.getFrameTree');
return frameTree.frame.id;
} finally {
await cdpSession.detach().catch(() => {});
}
}
/**
* Normalizes proxy options for Playwright.View on GitHub (pinned to dbe57fb09c)
Solutions
- Increase waitForStagehandToRegisterPage timeout if it is a slow-attach race (though persistent failure means registration never happens)
- Remove anything intercepting or blocking CDP sessions (extensions, proxies on the DevTools channel)
- Use a standard Chromium build compatible with Stagehand's helper script injection
- Check the page stays open and on its initial target long enough for registration
- Update @browserbasehq/stagehand and crawlee packages — registration bugs are fixed upstream periodically
Example fix
// before
const crawler = new StagehandCrawler({ /* default 10s */ });
// after
const crawler = new StagehandCrawler({
browserPoolOptions: {
browserPlugins: [new StagehandPlugin({ /* ensure stock chromium, no CDP interception */ })],
},
}); // and avoid navigating the page before the requestHandler starts Defensive patterns
Strategy: retry
Validate before calling
// Pre-check: ensure the page has a stable main frame before waiting
await page.waitForFunction(() => document.readyState !== 'loading', { timeout: 10_000 }).catch(() => {}); Type guard
const isRegistrationTimeout = (e) => e instanceof Error && /did not register the page within \d+ms/.test(e.message);
Try / catch
try {
const page = await browserPool.newPage();
} catch (err) {
if (isRegistrationTimeout(err)) {
log.error('Stagehand could not install its CDP helper — do NOT just retry blindly; check CDP blockers');
}
throw err;
} Prevention
- Use stock Chromium without extensions or CDP-intercepting tools
- Do not navigate the page before Stagehand registers it
- Allow a generous registration timeout for slow environments
- Keep @browserbasehq/stagehand updated to the version compatible with your crawlee release
When it happens
Trigger: _newPage → waitForStagehandToRegisterPage polling loop exhausts timeoutMs because Stagehand's CDP session init script installation failed (CDP target detached, intercepted CDP traffic, unsupported/patched Chromium), or the page navigated/closed before Stagehand could register it.
Common situations: Running against Chromium variants that block CDP script injection, other automation intercepting CDP sessions, extremely short custom timeoutMs, or heavy pages that navigate away instantly after creation.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- No browser context available
- Failed to get CDP URL from Stagehand
- The current SessionPool instance couldn't find a valid sessi
- Navigation timed out after ${this.#navigationTimeoutMillis /
- Function `newBrowserCDPSession()` is not available in incogn
AI-assisted analysis of apify/crawlee@dbe57fb09c (2026-08-30).
Data as JSON: /api/errors/591d2164fb59a597.
Report an issue: GitHub.