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

  1. Remove `skipNavigation: true` from the request/crawler options.
  2. Parse `context.body` (raw HTML) with cheerio rather than using document APIs.
  3. Split the crawl: skipNavigation requests for metadata-only, normal requests for DOM parsing.
  4. 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

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


AI-assisted analysis of apify/crawlee@dbe57fb09c (2026-08-30). Data as JSON: /api/errors/1342bcf10c9504ff. Report an issue: GitHub.