{"record":{"id":"887ee4dff8d271b5","repo":"apify/crawlee","slug":"the-document-property-is-not-available-skipna","errorCode":null,"errorMessage":"The `document` property is not available - `skipNavigation` was used","messagePattern":"The `document` property is not available - `skipNavigation` was used","errorType":"exception","errorClass":"NavigationSkippedError","httpStatus":null,"severity":"error","filePath":"packages/jsdom-crawler/src/internals/jsdom-crawler.ts","lineNumber":377,"sourceCode":"                },\n            };\n        } catch (err) {\n            if (err instanceof NavigationSkippedError) {\n                return {\n                    get window(): DOMWindow {\n                        throw new NavigationSkippedError(\n                            'The `window` property is not available - `skipNavigation` was used',\n                            { cause: err },\n                        );\n                    },\n                    get body(): string {\n                        throw new NavigationSkippedError(\n                            'The `body` property is not available - `skipNavigation` was used',\n                            { cause: err },\n                        );\n                    },\n                    get document(): Document {\n                        throw new NavigationSkippedError(\n                            'The `document` property is not available - `skipNavigation` was used',\n                            { cause: err },\n                        );\n                    },\n                };\n            }\n\n            throw err;\n        }\n    }\n\n    private async addHelpers(crawlingContext: InternalHttpCrawlingContext & { body: string; window: DOMWindow }) {\n        const addRequests = crawlingContext.addRequests;\n\n        const extractLinks = async (options?: ExtractLinksOptions): Promise<string[]> => {\n            if (!crawlingContext.window) {\n                throw new Error('Cannot extract links because the JSDOM is not available.');\n            }","sourceCodeStart":359,"sourceCodeEnd":395,"githubUrl":"https://github.com/apify/crawlee/blob/dbe57fb09ca607ad59dcf998f3925ef9ac3bb26c/packages/jsdom-crawler/src/internals/jsdom-crawler.ts#L359-L395","documentation":"Same skipNavigation mechanism: `context.document` normally returns the JSDOM `window.document`, but with navigation skipped no document exists, so the getter throws NavigationSkippedError to prevent silent `undefined` DOM operations.","triggerScenarios":"Accessing `context.document` (e.g. `context.document.querySelector(...)`) inside a JSDOMCrawler handler running with `skipNavigation: true`.","commonSituations":"Parsing pages with document APIs after enabling skipNavigation for performance; running preNavigationHooks/postNavigationHooks that use document; shared crawlers where some request options set skipNavigation dynamically.","solutions":["Remove `skipNavigation: true` from the request/crawler options.","Parse `context.body` with cheerio instead of using document.querySelector.","Route DOM-requiring requests to a non-skipNavigation crawler variant.","Check `request` options at the top of the handler and bail out before DOM access."],"exampleFix":"// before (skipNavigation: true)\nconst title = context.document.querySelector('title')?.textContent;\n\n// after\nconst cheerio = await import('cheerio');\nconst $ = cheerio.load(context.body);\nconst title = $('title').text();","handlingStrategy":"try-catch","validationCode":"if (request.skipNavigation === true) {\n    throw new Error('This handler requires a document; disable skipNavigation for this request');\n}","typeGuard":"function hasDocument(ctx: object): ctx is { document: Document } {\n    return 'document' in ctx && (ctx as any).document !== undefined;\n}","tryCatchPattern":"let $: cheerio.CheerioAPI | null = null;\ntry {\n    const doc = context.document;\n    $ = loadFromDocument(doc);\n} catch (err) {\n    if ((err as Error).message.includes('`skipNavigation` was used')) {\n        $ = (await import('cheerio')).load(context.body);\n    } else {\n        throw err;\n    }\n}","preventionTips":["Route document-dependent handlers to crawlers without skipNavigation.","Centralize DOM access behind a helper that falls back to cheerio parsing.","Assert at crawl start which requests are skipNavigation and which handlers they use.","Log request.userData.skipNavigation in error reports for faster diagnosis."],"tags":["jsdom","skip-navigation","dom","api-misuse"],"backgroundTag":"dom-unavailable-skip-navigation","analyzedSha":"dbe57fb09ca607ad59dcf998f3925ef9ac3bb26c","analyzedAt":"2026-08-30T22:22:28.328Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}