apify/crawlee · error
AdaptivePlaywrightCrawler requires transactional storage - i
Error message
AdaptivePlaywrightCrawler requires transactional storage - it runs the request handler multiple times per request and must be able to discard the storage writes of losing attempts. `transactionalStorage: false` is therefore not supported; a write policy object is accepted and forwarded to the per-attempt transactions.
What it means
AdaptivePlaywrightCrawler may run the request handler up to twice per request (once with a static fetch, once with a browser) and uses transactional storage to discard writes made by the losing attempt. Disabling transactional storage (`transactionalStorage: false`) would make those writes un-discardable, so the constructor rejects it outright.
Source
Thrown at packages/playwright-crawler/src/internals/adaptive-playwright-crawler.ts:372
// The extra fields are only tracked if the injected instance was built with them - the types enforce that,
// but plain JS callers would otherwise silently increment `undefined` into a sticky `NaN`. Extend
// `adaptivePlaywrightCrawlerStatisticState` to satisfy this.
if (statistics !== undefined) {
parseArgument(
statistics.state,
z.object({
httpOnlyRequestHandlerRuns: z.number(),
browserRequestHandlerRuns: z.number(),
renderingTypeMispredictions: z.number(),
}),
'statistics.state',
);
}
// Per-attempt buffering is load-bearing here: the handler runs up to twice per request and the
// losing attempt's writes must be discardable.
if (transactionalStorage === false) {
throw new Error(
'AdaptivePlaywrightCrawler requires transactional storage - it runs the request handler ' +
'multiple times per request and must be able to discard the storage writes of losing ' +
'attempts. `transactionalStorage: false` is therefore not supported; a write policy ' +
'object is accepted and forwarded to the per-attempt transactions.',
);
}
super({
...rest,
errorHandler,
failedRequestHandler,
requestHandler,
requestHandlerTimeoutSecs,
// The base would build a `Statistics` without the adaptive fields, so provide a default that has them.
// The cast covers a `StatisticStateExtension` that adds further fields - those can only come from an
// injected instance, in which case this default is never built.
statistics:
statistics ??View on GitHub (pinned to dbe57fb09c)
Solutions
- Remove `transactionalStorage: false` from the AdaptivePlaywrightCrawler options (the default is correct).
- If you need to tune write behavior, pass a write policy object instead of `false`; it is forwarded to the per-attempt transactions.
- If you truly cannot use transactional storage, switch to CheerioCrawler or PlaywrightCrawler, which do not retry handlers with alternative rendering.
Example fix
// before
const crawler = new AdaptivePlaywrightCrawler({ transactionalStorage: false });
// after
const crawler = new AdaptivePlaywrightCrawler({}); // default transactional storage required Defensive patterns
Strategy: validation
Validate before calling
if (options.transactionalStorage === false) {
throw new Error('AdaptivePlaywrightCrawler does not support transactionalStorage: false.');
} Try / catch
let crawler;
try {
crawler = new AdaptivePlaywrightCrawler(options);
} catch (err) {
if (err.message.includes('transactional storage')) {
delete options.transactionalStorage;
crawler = new AdaptivePlaywrightCrawler(options);
} else {
throw err;
}
} Prevention
- Never copy `transactionalStorage: false` from PlaywrightCrawler/CheerioCrawler configs into AdaptivePlaywrightCrawler options.
- Pass a write policy object (or omit the option) instead of `false` to tune storage writes.
- Document in shared crawler-factory code that AdaptivePlaywrightCrawler requires transactional storage.
- Add a unit test asserting crawler construction succeeds with your option set.
When it happens
Trigger: Constructing `new AdaptivePlaywrightCrawler({ transactionalStorage: false })`.
Common situations: Copying crawler options from PlaywrightCrawler/CheerioCrawler configurations where `transactionalStorage: false` is valid; disabling transactions to reduce storage overhead without realizing AdaptivePlaywrightCrawler depends on them.
Related errors
- Cannot open storage with alias "${alias}" because a named st
- Cannot open storage with name "${name}" because an alias sto
- 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/d68bf2c2e5b47fa7.
Report an issue: GitHub.