apify/crawlee · error · Error
Cannot honour a crawl-delay floor covering every domain: thi
Error message
Cannot honour a crawl-delay floor covering every domain: this manager only paces the domains it was given (${Array.from(this.#listedDomains).join(', ')}), so everything else would run unpaced. Set `domains: 'all'` to pace whatever the crawl encounters, or declare the floor on this manager yourself via `minCrawlDelaySecs`. What it means
When a server sends a crawl-delay (robots.txt) pacing signal scoped to all domains, the manager refuses to apply it unless it actually throttles every domain (`domains: 'all'`). With an explicit domain list, other domains would run unpaced, so it throws instead of silently under-pacing.
Source
Thrown at packages/core/src/storages/throttling_request_manager.ts:634
/**
* The runtime form of {@apilink ThrottlingRequestManagerOptions.minCrawlDelaySecs|`minCrawlDelaySecs`}: raises
* the floor under every throttled domain's crawl delay.
*
* @returns `false` if this manager paces nothing at all, so there is no floor to raise.
* @throws If it paces some domains but not all - holding back only those would leave the rest of what the
* floor covers unpaced.
*/
#recordEverywhereFloor(intervalMs: number, scope: PacingScope): boolean {
// Before the scope check: a manager that paces nothing has no grouping worth objecting about, and
// `false` lets the caller pace it from outside.
if (!this.#throttlingEnabled) {
return false;
}
this.#assertScopeHonourable(scope);
if (!this.#throttlesEveryDomain) {
throw new Error(
`Cannot honour a crawl-delay floor covering every domain: this manager only paces the domains ` +
`it was given (${Array.from(this.#listedDomains).join(', ')}), so everything else would run ` +
`unpaced. Set \`domains: 'all'\` to pace whatever the crawl encounters, or declare the floor ` +
`on this manager yourself via \`minCrawlDelaySecs\`.`,
);
}
this.#minCrawlDelayMs = Math.max(this.#minCrawlDelayMs, intervalMs);
this.log.debug(`Crawl-delay floor for every domain set to ${(this.#minCrawlDelayMs / 1000).toFixed(1)}s`);
return true;
}
/**
* Throws unless a signal scoped to `scope` can be honoured as declared or wider.
*
* Holding a domain back means holding its queue back, so
* {@apilink ThrottlingRequestManagerOptions.throttleBy|`throttleBy`} is the finest granularity this managerView on GitHub (pinned to dbe57fb09c)
Solutions
- Construct the manager with `domains: 'all'` so it can pace any encountered domain
- Set `minCrawlDelaySecs` on the manager yourself to declare the floor explicitly
- Narrow the signal scope so it targets only the domains the manager lists
- Add the relevant domain(s) to `domains` if partial coverage is actually intended (then scope the signal accordingly)
Example fix
// before
const mgr = new ThrottlingRequestManager({ domains: ['example.com'] });
mgr.recordPacingSignal({ scope: 'everywhere', minDelaySecs: 5 }); // throws
// after
const mgr = new ThrottlingRequestManager({ domains: 'all', minCrawlDelaySecs: 5 }); Defensive patterns
Strategy: try-catch
Validate before calling
const canHonourEverywhere =
managerConfig.domains === 'all' || managerConfig.minCrawlDelaySecs != null;
if (signal.scope === 'everywhere' && !canHonourEverywhere) {
// skip signal or reconfigure manager before calling recordPacingSignal
} Type guard
null
Try / catch
try {
manager.recordPacingSignal(signal);
} catch (err) {
if (/Cannot honour a crawl-delay floor/.test(String(err))) {
logger.warning('Crawl-delay floor ignored: manager scope too narrow');
} else throw err;
} Prevention
- Use domains: 'all' when relaying robots.txt crawl-delays
- Declare minCrawlDelaySecs explicitly if you need a global floor
- Keep pacing-signal emitters aware of the manager's domains configuration
When it happens
Trigger: Calling recordPacingSignal with an everywhere/registrable-wide crawl-delay floor while the manager was constructed with an explicit `domains` array (not 'all').
Common situations: Robots.txt of some site declares a global crawl-delay and the crawler relays it to a manager configured for a fixed domain list; developers assume the manager applies floors globally by default.
Related errors
- "${domain}" is not a valid hostname. The `domains` option ta
- Cannot honour a pacing signal scoped to "${scope}": this man
- The `minConcurrency`/`maxConcurrency`/`initialConcurrency`/`
- The `requestManager` option cannot be used in conjunction wi
- Cannot decide what to purge before running again: `sameDomai
AI-assisted analysis of apify/crawlee@dbe57fb09c (2026-08-30).
Data as JSON: /api/errors/885adf5246faf3e8.
Report an issue: GitHub.