{"record":{"id":"8a790fe18acdb409","repo":"apify/crawlee","slug":"skipping-request-request-id-starting-url-re","errorCode":null,"errorMessage":"Skipping request ${request.id} (starting url: ${request.url} -> loaded url: ${request.loadedUrl}) because it does not match the enqueue strategy (${request['enqueueStrategy']}).","messagePattern":"Skipping request (.+?) \\(starting url: (.+?) -> loaded url: (.+?)\\) because it does not match the enqueue strategy \\((.+?)\\)\\.","errorType":"exception","errorClass":"ContextPipelineInterruptedError","httpStatus":null,"severity":"warning","filePath":"packages/basic-crawler/src/internals/basic-crawler.ts","lineNumber":1594,"sourceCode":"                ) as unknown as ContextPipeline<CrawlingContext, Context>;\n        } else {\n            contextPipeline = subclassPipeline;\n        }\n\n        contextPipeline = contextPipeline.compose({\n            action: async (context) => {\n                const { request } = context;\n                if (request && !this.requestMatchesEnqueueStrategy(request)) {\n                    // eslint-disable-next-line dot-notation\n                    const message = `Skipping request ${request.id} (starting url: ${request.url} -> loaded url: ${request.loadedUrl}) because it does not match the enqueue strategy (${request['enqueueStrategy']}).`;\n                    this.log.debug(message);\n\n                    request.noRetry = true;\n                    request.state = RequestState.SKIPPED;\n\n                    await this.#handleSkippedRequest({ request, reason: 'redirect' });\n\n                    throw new ContextPipelineInterruptedError(message);\n                }\n                return context;\n            },\n        });\n\n        return contextPipeline as ContextPipeline<CrawlingContext, ExtendedContext>;\n    }\n\n    /**\n     * Checks if the given error is a proxy error by comparing its message to a list of known proxy error messages.\n     * Used for retrying requests that failed due to proxy errors.\n     *\n     * @param error The error to check.\n     */\n    protected isProxyError(error: Error): boolean {\n        return ROTATE_PROXY_ERRORS.some((x: string) => (this.getMessageFromError(error) as any)?.includes(x));\n    }\n","sourceCodeStart":1576,"sourceCodeEnd":1612,"githubUrl":"https://github.com/apify/crawlee/blob/dbe57fb09ca607ad59dcf998f3925ef9ac3bb26c/packages/basic-crawler/src/internals/basic-crawler.ts#L1576-L1612","documentation":"After a redirect, the crawler checks whether the final loaded URL still satisfies the request's enqueue strategy (e.g. SAME_DOMAIN, SAME_HOSTNAME). If the redirect crossed outside the allowed scope, the request is marked SKIPPED, recorded as skipped with reason 'redirect', and the pipeline is interrupted with this error.","triggerScenarios":"A request enqueued with a restrictive enqueueStrategy (e.g. sameHostname) whose server responds with a redirect to a URL that violates that strategy — the loaded URL no longer matches, so the request is skipped.","commonSituations":"Sites redirecting http->a different subdomain, to a CDN domain, or to a country-specific domain; enqueuing with SAME_HOSTNAME and hitting a www/non-www or short-link redirect.","solutions":["Loosen the enqueue strategy (e.g. use EnqueueStrategy.SameDomain instead of SameHostname) if the redirects are legitimate.","Pre-resolve redirects with a HEAD/GET request and enqueue the final URL directly.","Handle the skipped 'redirect' requests in the skipped-request hook and re-enqueue the loadedUrl with an appropriate strategy.","Add the redirect target's domain to the allowed domains in strategy options if it should be followed."],"exampleFix":"// before\nconst crawler = new CheerioCrawler({ enqueueStrategy: { strategy: 'same-hostname' } });\n// after\nconst crawler = new CheerioCrawler({ enqueueStrategy: { strategy: 'same-domain' } });","handlingStrategy":"validation","validationCode":"// Verify the final URL of a request stays inside the strategy before enqueueing\nconst finalUrl = await resolveRedirects(request.url); // HEAD-follow helper\nif (!isSameDomain(finalUrl, new URL(request.url).hostname)) {\n  request.enqueueStrategy = { strategy: 'same-domain' }; // loosen or skip enqueueing\n}","typeGuard":"function matchesStrategy(loadedUrl, originUrl, strategy) {\n  const a = new URL(loadedUrl), b = new URL(originUrl);\n  if (strategy === 'same-hostname') return a.hostname === b.hostname;\n  if (strategy === 'same-domain') return a.hostname.replace(/^www\\./, '') === b.hostname.replace(/^www\\./, '');\n  return true;\n}","tryCatchPattern":"try {\n  await crawler.run(requests);\n} catch (err) {\n  if (err.name === 'ContextPipelineInterruptedError' && err.message.includes('enqueue strategy')) {\n    // treat request as skipped; optionally re-enqueue request.loadedUrl with a looser strategy\n  } else throw err;\n}","preventionTips":["Choose the enqueue strategy based on known redirect behavior of target sites.","Prefer same-domain over same-hostname when sites redirect between subdomains.","Re-enqueue request.loadedUrl explicitly when you want to follow cross-scope redirects.","Audit skipped-request reports for 'redirect' reasons to spot strategy mismatches early."],"tags":["redirect","enqueue-strategy","skipped-request"],"backgroundTag":"redirect-strategy-mismatch","analyzedSha":"dbe57fb09ca607ad59dcf998f3925ef9ac3bb26c","analyzedAt":"2026-08-30T22:22:28.328Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}