{"record":{"id":"7366e6655de9e95f","repo":"apify/crawlee","slug":"cannot-extract-links-because-the-dom-is-not-availa","errorCode":null,"errorMessage":"Cannot extract links because the DOM is not available.","messagePattern":"Cannot extract links because the DOM is not available\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cheerio-crawler/src/internals/cheerio-crawler.ts","lineNumber":271,"sourceCode":"                    get $(): CheerioAPI {\n                        throw new NavigationSkippedError(\n                            'The `$` 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 & { $: CheerioAPI }) {\n        const addRequests = crawlingContext.addRequests;\n\n        const extractLinks = async (options?: ExtractLinksOptions): Promise<string[]> => {\n            if (!crawlingContext.$) {\n                throw new Error('Cannot extract links because the DOM is not available.');\n            }\n\n            return extractUrlsFromCheerio(\n                crawlingContext.$,\n                options?.selector ?? 'a',\n                options?.baseUrl ?? crawlingContext.request.loadedUrl ?? crawlingContext.request.url,\n            );\n        };\n\n        return {\n            extractLinks,\n            enqueueLinks: async (options: EnqueueLinksOptions = {}) => {\n                const baseUrl = resolveBaseUrlForEnqueueLinksFiltering({\n                    enqueueStrategy: options.strategy,\n                    finalRequestUrl: crawlingContext.request.loadedUrl,\n                    originalRequestUrl: crawlingContext.request.url,\n                    userProvidedBaseUrl: options.baseUrl,\n                });","sourceCodeStart":253,"sourceCodeEnd":289,"githubUrl":"https://github.com/apify/crawlee/blob/dbe57fb09ca607ad59dcf998f3925ef9ac3bb26c/packages/cheerio-crawler/src/internals/cheerio-crawler.ts#L253-L289","documentation":"CheerioCrawler's `extractLinks` helper (backing `enqueueLinks`) needs a parsed DOM (`$`) to select link elements. If the crawling context has no `$` — e.g. skipNavigation was used or the response was not HTML — the helper throws immediately instead of scanning an empty document.","triggerScenarios":"Calling `enqueueLinks()` / `extractLinks()` in a handler where `crawlingContext.$` is undefined, typically with `skipNavigation: true` or a non-HTML response.","commonSituations":"Enabling skipNavigation on a crawler that also enqueues links; running enqueueLinks on binary/JSON endpoints where Cheerio parsing was skipped.","solutions":["Remove `skipNavigation` so the response is parsed into `$` before enqueueLinks runs.","Move `enqueueLinks` to a handler path that only runs for HTML responses.","Enqueue requests manually via `addRequests` with URLs derived from `request.url` or the API response instead of DOM extraction."],"exampleFix":"// before\nnew CheerioCrawler({ skipNavigation: true, requestHandler: async ({ enqueueLinks }) => { await enqueueLinks(); } });\n// after\nnew CheerioCrawler({ requestHandler: async ({ enqueueLinks }) => { await enqueueLinks(); } });","handlingStrategy":"type-guard","validationCode":"if (!('$' in context) || !context.$) { log.warning('enqueueLinks skipped: no DOM'); return; }","typeGuard":"function hasDom(ctx: CrawlingContext): ctx is CrawlingContext & { $: CheerioAPI } { return '$' in ctx && Boolean((ctx as any).$); }","tryCatchPattern":"try { await enqueueLinks(); } catch (err) { if (err.message.includes('DOM is not available')) { await context.addRequests([{ url: alternateUrl }]); } else { throw err; } }","preventionTips":["Only call enqueueLinks from handlers where the response was parsed","Check `context.$` truthiness before link extraction","Avoid skipNavigation on crawlers that need to follow discovered links"],"tags":["cheerio-crawler","enqueue-links","dom-unavailable"],"backgroundTag":"dom-not-available-for-link-extraction","analyzedSha":"dbe57fb09ca607ad59dcf998f3925ef9ac3bb26c","analyzedAt":"2026-08-30T22:22:28.328Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}