apify/crawlee · error · NavigationSkippedError

The `response` property is not available - `skipNavigation`

Error message

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

What it means

With skipNavigation requests there is no browser response, so the context's `response` getter throws NavigationSkippedError instead of returning null, signalling that navigation was intentionally skipped and no response exists.

Source

Thrown at packages/browser-crawler/src/internals/browser-crawler.ts:647

            },
        };
    }

    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 it
            // to the remaining shared window unless a hook overrode it (see there).
            gotoOptions: { timeout: this.#navigationTimeoutMillis } as unknown as GoToOptions,
            [COOKIES_BEFORE_HOOKS]: this.getCookieHeaderFromRequest(crawlingContext.request),
        } as unknown as Partial<Context>;
    }

    private async navigate(crawlingContext: Context): Promise<Partial<Context>> {
        tryCancel();

View on GitHub (pinned to dbe57fb09c)

Solutions

  1. Only access response for requests without skipNavigation; branch on request.skipNavigation
  2. Use other context data (page state, request.userData, handler-produced values) for skip-navigation requests
  3. Remove skipNavigation if a response is genuinely needed

Example fix

// before
const status = ctx.response.status;
// after
if (!ctx.request.skipNavigation) {
    const status = ctx.response.status;
}
Defensive patterns

Strategy: type-guard

Validate before calling

if (ctx.request.skipNavigation) { /* skip response usage */ } else { useResponse(ctx.response); }

Type guard

function hasBrowserResponse<T extends { request: Request; response?: Response }>(ctx: T): boolean {
    return !ctx.request.skipNavigation;
}

Try / catch

try { const res = ctx.response; /* use res */ } catch (e) { if (/skipNavigation/.test(String(e.message))) { /* no response expected */ } else throw e; }

Prevention

When it happens

Trigger: Reading crawlingContext.response from the handler/hook of a request that was enqueued with skipNavigation: true.

Common situations: Handlers that inspect response for all requests; shared handler code paths used by both navigating and skip-navigation requests; about:-style no-navigation requests whose results come from elsewhere.

Related errors


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