apify/crawlee · error · NavigationSkippedError

The `body` property is not available - `skipNavigation` was

Error message

The `body` property is not available - `skipNavigation` was used

What it means

Crawlee's CheerioCrawler lets a request handler opt out of downloading the response body via `skipNavigation`. When that option is used, the `body` property of the crawling context is replaced with a getter that throws NavigationSkippedError on access, because no body was ever fetched.

Source

Thrown at packages/cheerio-crawler/src/internals/cheerio-crawler.ts:248

        try {
            const isXml = crawlingContext.contentType.type.includes('xml');
            const body = Buffer.isBuffer(crawlingContext.body)
                ? crawlingContext.body.toString(crawlingContext.contentType.encoding)
                : crawlingContext.body;
            const dom = parseDocument(body, { decodeEntities: true, xmlMode: isXml });
            const $ = cheerio.load(dom, {
                xml: { decodeEntities: true, xmlMode: isXml },
            } as CheerioOptions);

            return {
                $,
                body,
            };
        } catch (err) {
            if (err instanceof NavigationSkippedError) {
                return {
                    get body(): string {
                        throw new NavigationSkippedError(
                            'The `body` property is not available - `skipNavigation` was used',
                            { cause: err },
                        );
                    },
                    get $(): CheerioAPI {
                        throw new NavigationSkippedError(
                            'The `$` property is not available - `skipNavigation` was used',
                            { cause: err },
                        );
                    },
                };
            }

            throw err;
        }
    }

    private async addHelpers(crawlingContext: InternalHttpCrawlingContext & { $: CheerioAPI }) {

View on GitHub (pinned to dbe57fb09c)

Solutions

  1. Stop reading `body` in the handler when skipNavigation is enabled; rely on `request.url`, response headers, or enqueue links only.
  2. Remove `skipNavigation: true` from the crawler options if the response body is actually needed.
  3. Guard access: check a `skipNavigation` flag on the crawler options before touching `body`.

Example fix

// before
const crawler = new CheerioCrawler({ skipNavigation: true, requestHandler: ({ body }) => { parse(body); } });
// after
const crawler = new CheerioCrawler({ skipNavigation: true, requestHandler: ({ request, enqueueLinks }) => { enqueueLinks(); } });
Defensive patterns

Strategy: validation

Validate before calling

if (crawlerOptions.skipNavigation) { throw new Error('handler reads `body` but skipNavigation is enabled'); }

Type guard

function hasBody(ctx: object): ctx is { body: string } { return 'body' in ctx && !isNavigationSkipped(ctx); }

Try / catch

try { use(context.body); } catch (err) { if (err instanceof NavigationSkippedError) { /* handle missing body */ } else { throw err; } }

Prevention

When it happens

Trigger: Accessing `crawlingContext.body` (or destructuring `{ body }` from the context) inside a requestHandler while the crawler/request was configured with `skipNavigation: true`.

Common situations: Switching a crawler to `skipNavigation` for speed and forgetting that old handler code still reads `body`; copying handler code between a CheerioCrawler with and without skipNavigation.

Related errors


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