{"record":{"id":"d68bf2c2e5b47fa7","repo":"apify/crawlee","slug":"adaptiveplaywrightcrawler-requires-transactional-s","errorCode":null,"errorMessage":"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.","messagePattern":"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\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/playwright-crawler/src/internals/adaptive-playwright-crawler.ts","lineNumber":372,"sourceCode":"        // The extra fields are only tracked if the injected instance was built with them - the types enforce that,\n        // but plain JS callers would otherwise silently increment `undefined` into a sticky `NaN`. Extend\n        // `adaptivePlaywrightCrawlerStatisticState` to satisfy this.\n        if (statistics !== undefined) {\n            parseArgument(\n                statistics.state,\n                z.object({\n                    httpOnlyRequestHandlerRuns: z.number(),\n                    browserRequestHandlerRuns: z.number(),\n                    renderingTypeMispredictions: z.number(),\n                }),\n                'statistics.state',\n            );\n        }\n\n        // Per-attempt buffering is load-bearing here: the handler runs up to twice per request and the\n        // losing attempt's writes must be discardable.\n        if (transactionalStorage === false) {\n            throw new Error(\n                'AdaptivePlaywrightCrawler requires transactional storage - it runs the request handler ' +\n                    'multiple times per request and must be able to discard the storage writes of losing ' +\n                    'attempts. `transactionalStorage: false` is therefore not supported; a write policy ' +\n                    'object is accepted and forwarded to the per-attempt transactions.',\n            );\n        }\n\n        super({\n            ...rest,\n            errorHandler,\n            failedRequestHandler,\n            requestHandler,\n            requestHandlerTimeoutSecs,\n            // The base would build a `Statistics` without the adaptive fields, so provide a default that has them.\n            // The cast covers a `StatisticStateExtension` that adds further fields - those can only come from an\n            // injected instance, in which case this default is never built.\n            statistics:\n                statistics ??","sourceCodeStart":354,"sourceCodeEnd":390,"githubUrl":"https://github.com/apify/crawlee/blob/dbe57fb09ca607ad59dcf998f3925ef9ac3bb26c/packages/playwright-crawler/src/internals/adaptive-playwright-crawler.ts#L354-L390","documentation":"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.","triggerScenarios":"Constructing `new AdaptivePlaywrightCrawler({ transactionalStorage: false })`.","commonSituations":"Copying crawler options from PlaywrightCrawler/CheerioCrawler configurations where `transactionalStorage: false` is valid; disabling transactions to reduce storage overhead without realizing AdaptivePlaywrightCrawler depends on them.","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."],"exampleFix":"// before\nconst crawler = new AdaptivePlaywrightCrawler({ transactionalStorage: false });\n\n// after\nconst crawler = new AdaptivePlaywrightCrawler({}); // default transactional storage required","handlingStrategy":"validation","validationCode":"if (options.transactionalStorage === false) {\n    throw new Error('AdaptivePlaywrightCrawler does not support transactionalStorage: false.');\n}","typeGuard":null,"tryCatchPattern":"let crawler;\ntry {\n    crawler = new AdaptivePlaywrightCrawler(options);\n} catch (err) {\n    if (err.message.includes('transactional storage')) {\n        delete options.transactionalStorage;\n        crawler = new AdaptivePlaywrightCrawler(options);\n    } else {\n        throw err;\n    }\n}","preventionTips":["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."],"tags":["configuration","storage","adaptive-playwright-crawler"],"backgroundTag":"unsupported-option-value","analyzedSha":"dbe57fb09ca607ad59dcf998f3925ef9ac3bb26c","analyzedAt":"2026-08-30T22:22:28.328Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}