apify/crawlee · error · SessionError
${this.getMessageFromError(error)}
Error message
${this.getMessageFromError(error)} What it means
`throwIfProxyError()` checks whether a navigation failure was caused by the proxy (via `isProxyError`) and, if so, converts it into a `SessionError` with the original message. This tells the crawler the failure is proxy-related so the session/proxy is retired and the request retried, instead of counting it as a normal request error.
Source
Thrown at packages/browser-crawler/src/internals/browser-crawler.ts:821
// Fire-and-forget: no user code will run on this page after a failed navigation.
// Swallow rejections: the page may already be detached.
void page.evaluate(() => window.stop()).catch(() => {});
if (isNavigationTimeoutError(error)) {
session?.markBad();
// The driver was handed the remaining window (usually shorter than `navigationTimeoutSecs` once the
// hooks have run), so it names that value in its own error; report the configured window instead.
throw new TimeoutError(`Navigation timed out after ${this.#navigationTimeoutMillis / 1000} seconds.`);
}
}
/**
* Transforms proxy-related errors to `SessionError`.
*/
private throwIfProxyError(error: Error) {
if (this.isProxyError(error)) {
throw new SessionError(this.getMessageFromError(error) as string);
}
}
protected abstract navigationHandler(
crawlingContext: BrowserCrawlingContext<Page, Response>,
gotoOptions: GoToOptions,
): Promise<Context['response'] | null | undefined>;
private async processResponse(
response: Response | undefined,
crawlingContext: BrowserCrawlingContext,
): Promise<void> {
const { session, request, page } = crawlingContext;
if (typeof response === 'object' && typeof response.status === 'function') {
const status: number = response.status();
this.statistics.registerStatusCode(status);View on GitHub (pinned to dbe57fb09c)
Solutions
- Verify the proxy is reachable: `curl -x http://host:port https://example.com` — fix or replace dead proxies
- Check credentials embedded in the proxy URL and rotate them if the proxy reports auth failures
- Configure multiple `proxyUrls` in `ProxyConfiguration` so failed proxies are rotated away from
- Ensure a session pool is used so the bad session/proxy combination is retired automatically
Example fix
// before
new PlaywrightCrawler({ proxyUrls: ['http://10.0.0.5:8080'] }); // proxy down
// after
const proxyConfiguration = await ProxyConfiguration.create({
proxyUrls: ['http://proxy1:8080', 'http://proxy2:8080'], // rotation provides fallback
});
new PlaywrightCrawler({ proxyConfiguration }); Defensive patterns
Strategy: validation
Validate before calling
// Verify proxy reachability before starting the crawl:
const res = await fetch('https://api.ipify.org', {
agent: new HttpsProxyAgent(proxyUrl),
signal: AbortSignal.timeout(10_000),
});
console.log('proxy OK, egress IP:', await res.text()); Type guard
function isProxySessionError(e: unknown): e is SessionError {
return e instanceof SessionError && /proxy|ERR_PROXY|407|tunnel/i.test(e.message);
} Try / catch
crawler.failedRequestHandler = async ({ request, error }) => {
if (error instanceof SessionError && /proxy/i.test(error.message)) {
log.error(`Proxy failed for ${request.url}: ${error.message} — rotate proxyUrls`);
}
}; Prevention
- Health-check proxies (curl -x ...) before long crawls
- Provide several proxyUrls so ProxyConfiguration can rotate
- Validate credentials in proxy URLs and monitor for 407 responses
When it happens
Trigger: `page.goto()` (or the underlying network stack) rejects with a proxy-specific error — e.g. `ERR_PROXY_CONNECTION_FAILED`, proxy authentication required (407), or tunnel connection refused — while navigating through a `proxyUrl`/`proxyConfiguration` with a dead or misconfigured proxy.
Common situations: Proxy server down or DNS unresolvable; wrong credentials in `http://user:pass@host:port` proxy URLs; proxy rate-limited or banned; using an expired paid proxy subscription; Docker/CI environments where the proxy host is unreachable.
Related errors
- <dynamic: message extracted from proxied error via getMessag
- Request blocked - received ${statusCode} status code.
- The current SessionPool instance couldn't find a valid sessi
- ${error} (possible values: 'Cloudflare challenge failed, fou
- Invalid "proxyUrl". Unsupported protocol: ${proxyUrl}.
AI-assisted analysis of apify/crawlee@dbe57fb09c (2026-08-30).
Data as JSON: /api/errors/0e311252b3011aca.
Report an issue: GitHub.