apify/crawlee · error · NavigationSkippedError
The `request.loadedUrl` property is not available - `skipNav
Error message
The `request.loadedUrl` property is not available - `skipNavigation` was used
What it means
When a request has skipNavigation set, the crawler never navigates, so request.loadedUrl is never populated. prepareNavigation wraps the request in a Proxy that throws NavigationSkippedError if loadedUrl is accessed, making the absence explicit.
Source
Thrown at packages/browser-crawler/src/internals/browser-crawler.ts:639
const urls = await extractLinks(options);
return addRequests(urls, {
...options,
baseUrl,
strategy: options.strategy ?? EnqueueStrategy.SameHostname,
});
},
};
}
private async prepareNavigation(crawlingContext: Context): Promise<Partial<Context>> {
if (crawlingContext.request.skipNavigation) {
return {
request: new Proxy(crawlingContext.request, {
get(target, propertyName, receiver) {
if (propertyName === 'loadedUrl') {
throw new NavigationSkippedError(
'The `request.loadedUrl` property is not available - `skipNavigation` was used',
);
}
return Reflect.get(target, propertyName, receiver);
},
}) as LoadedRequest<Request>,
get response(): Response {
throw new NavigationSkippedError(
'The `response` property is not available - `skipNavigation` was used',
);
},
} as Partial<Context>;
}
crawlingContext.request.state = RequestState.BEFORE_NAV;
return {
// Default to the full navigation timeout so a pre-navigation hook can read it; `navigate` narrows itView on GitHub (pinned to dbe57fb09c)
Solutions
- Don't read request.loadedUrl when skipNavigation is set; use request.url instead
- Guard with a check: if (!request.skipNavigation) access loadedUrl
- Remove skipNavigation if you actually need navigation and a loadedUrl
Example fix
// before const url = ctx.request.loadedUrl; // after const url = ctx.request.skipNavigation ? ctx.request.url : ctx.request.loadedUrl;
Defensive patterns
Strategy: type-guard
Validate before calling
const url = ctx.request.skipNavigation ? ctx.request.url : ctx.request.loadedUrl ?? ctx.request.url;
Type guard
function hasLoadedUrl(req: Request): boolean {
return !req.skipNavigation && typeof (req as LoadedRequest).loadedUrl === 'string';
} Try / catch
let loadedUrl: string;
try { loadedUrl = ctx.request.loadedUrl; } catch (e) { if (/skipNavigation/.test(String(e.message))) loadedUrl = ctx.request.url; else throw e; } Prevention
- Branch on request.skipNavigation before touching loadedUrl
- Use request.url as the canonical fallback
- Only set skipNavigation on requests whose handlers don't need navigation results
When it happens
Trigger: Adding a request with skipNavigation: true and then reading request.loadedUrl in the request handler or a hook.
Common situations: Requests used purely to trigger side-effect handlers (API calls, uploads) without navigation; users assuming loadedUrl is always set after a request is processed.
Related errors
- The `response` property is not available - `skipNavigation`
- The `response` property is not available. This might mean th
- The `gotoOptions` property is not available until `prepareNa
- This crawler instance is already running, you can add more r
- fetchNextRequest called on an uninitialized crawler
AI-assisted analysis of apify/crawlee@dbe57fb09c (2026-08-30).
Data as JSON: /api/errors/490069e76c222ec5.
Report an issue: GitHub.