apify/crawlee · error · NavigationSkippedError
The `window` property is not available - `skipNavigation` wa
Error message
The `window` property is not available - `skipNavigation` was used
What it means
LinkedomCrawler mirrors JSDOMCrawler's skipNavigation design: with navigation skipped, no parse5/linkedom window is built, and the `window` property getter throws NavigationSkippedError to signal that DOM access is not possible in this mode.
Source
Thrown at packages/linkedom-crawler/src/internals/linkedom-crawler.ts:248
crawlingContext.body.toString(),
isXml ? 'text/xml' : 'text/html',
);
return {
window: document.defaultView,
get body() {
return document.documentElement.outerHTML;
},
get document() {
// See comment about typing in LinkeDOMCrawlingContext definition
return document as unknown as Document;
},
};
} catch (err) {
if (err instanceof NavigationSkippedError) {
return {
get window(): Window {
throw new NavigationSkippedError(
'The `window` property is not available - `skipNavigation` was used',
{ cause: err },
);
},
get body(): string {
throw new NavigationSkippedError(
'The `body` property is not available - `skipNavigation` was used',
{ cause: err },
);
},
get document(): Document {
throw new NavigationSkippedError(
'The `document` property is not available - `skipNavigation` was used',
{ cause: err },
);
},
};
}View on GitHub (pinned to dbe57fb09c)
Solutions
- Remove `skipNavigation: true` if DOM/window access is needed.
- Use `context.body` (raw string) and parse with cheerio or regex instead.
- Branch the handler based on navigation-skip state before touching `window`.
- Use extractLinks only on requests where the window was actually created.
Example fix
// before (skipNavigation: true)
const links = [...context.window.document.querySelectorAll('a')];
// after
const $ = (await import('cheerio')).load(context.body);
const links = $('a[href]').toArray(); Defensive patterns
Strategy: try-catch
Validate before calling
if (request.skipNavigation === true) {
// context.window will throw; use cheerio on context.body instead
} Type guard
function isNavigationSkippedError(err: unknown): err is Error & { name: 'NavigationSkippedError' } {
return err instanceof Error && err.name === 'NavigationSkippedError';
} Try / catch
try {
const { window } = context;
parse(window);
} catch (err) {
if ((err as Error).message.includes('`skipNavigation` was used')) {
parseCheerio(context.body);
} else {
throw err;
}
} Prevention
- Guard all window access behind a skipNavigation check.
- Use separate handlers for skipNavigation vs parsing crawls.
- Store skipNavigation flag in request.userData for easy branching.
- Add tests that exercise handlers in both navigation modes.
When it happens
Trigger: Using LinkedomCrawler with `skipNavigation: true` and then reading `context.window` in the requestHandler.
Common situations: Performance-tuned linkedom crawls with skipNavigation but handlers that still call window-based helpers (enqueueLinks, extractLinks); handlers shared between linkedom and normal crawlers.
Related errors
- The `body` property is not available - `skipNavigation` was
- The `document` property is not available - `skipNavigation`
- The `window` property is not available - `skipNavigation` wa
- The `body` property is not available - `skipNavigation` was
- The `document` property is not available - `skipNavigation`
AI-assisted analysis of apify/crawlee@dbe57fb09c (2026-08-30).
Data as JSON: /api/errors/9b4691d0345ee6f9.
Report an issue: GitHub.