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
- Stop reading `body` in the handler when skipNavigation is enabled; rely on `request.url`, response headers, or enqueue links only.
- Remove `skipNavigation: true` from the crawler options if the response body is actually needed.
- 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
- Keep skipNavigation crawlers' handlers free of body/$ access
- Don't share one request handler between parsing and navigation-only crawlers
- Destructure only the context fields you know exist for the configured options
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
- The `$` property is not available - `skipNavigation` was use
- The `window` property is not available - `skipNavigation` wa
- The `body` property is not available - `skipNavigation` was
- The `document` property is not available - `skipNavigation`
- The `window` property is not available - `skipNavigation` wa
AI-assisted analysis of apify/crawlee@dbe57fb09c (2026-08-30).
Data as JSON: /api/errors/efec951d62dbc948.
Report an issue: GitHub.