apify/crawlee · error · NavigationSkippedError
The `document` property is not available - `skipNavigation`
Error message
The `document` property is not available - `skipNavigation` was used
What it means
Same as the jsdom counterpart: with `skipNavigation` in LinkedomCrawler, `context.document` (normally the linkedom Document) is a getter that throws NavigationSkippedError because no document tree was ever constructed.
Source
Thrown at packages/linkedom-crawler/src/internals/linkedom-crawler.ts:260
},
};
} 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 },
);
},
};
}
throw err;
}
}
private async addHelpers(crawlingContext: InternalHttpCrawlingContext & { body: string; window: Window }) {
const addRequests = crawlingContext.addRequests;
const extractLinks = async (options?: ExtractLinksOptions): Promise<string[]> => {
if (!crawlingContext.window) {
throw new Error('Cannot extract links because the DOM is not available.');
}View on GitHub (pinned to dbe57fb09c)
Solutions
- Remove `skipNavigation: true` from the request/crawler options.
- Parse `context.body` (raw HTML) with cheerio rather than using document APIs.
- Split the crawl: skipNavigation requests for metadata-only, normal requests for DOM parsing.
- Add an early check in the handler to throw a clearer domain-specific error when document is unavailable.
Example fix
// before (skipNavigation: true)
const headings = [...context.document.querySelectorAll('h2')];
// after
const $ = (await import('cheerio')).load(context.body);
const headings = $('h2').toArray(); Defensive patterns
Strategy: try-catch
Validate before calling
if (request.skipNavigation === true) {
// context.document will throw; switch to string parsing
} Type guard
function hasDocument(ctx: object): ctx is { document: Document } {
return 'document' in ctx && (ctx as any).document !== undefined;
} Try / catch
try {
const text = context.document.body?.textContent;
use(text);
} catch (err) {
if ((err as Error).message.includes('`skipNavigation` was used')) {
use(cheerio.load(context.body).text());
} else {
throw err;
}
} Prevention
- Disable skipNavigation for handlers that rely on document APIs.
- Wrap document access in a utility that falls back to cheerio.
- Validate crawl config so document-requiring handlers never get skipNavigation requests.
- Catch NavigationSkippedError by name/message in shared helpers.
When it happens
Trigger: Accessing `context.document` (e.g. `context.document.getElementsByTagName(...)`) in a LinkedomCrawler handler while `skipNavigation: true` is active.
Common situations: Migrating JSDOMCrawler handlers to LinkedomCrawler without realizing skipNavigation strips document/window/body; postNavigationHooks that query the document.
Related errors
- The `window` property is not available - `skipNavigation` wa
- The `body` property is not available - `skipNavigation` was
- 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/1342bcf10c9504ff.
Report an issue: GitHub.