apify/crawlee · error · Error
Cannot persist state. options.persistStateKey is not set.
Error message
Cannot persist state. options.persistStateKey is not set.
What it means
persistState() saves the list's processed-position state to the default KeyValueStore, but only when a persistStateKey was configured at construction. Without the key there is nowhere to persist, so the method throws instead of silently doing nothing.
Source
Thrown at packages/core/src/storages/request_list.ts:458
// oxlint-disable-next-line typescript/no-array-delete -- intentional, drop the slot so V8 can collect the object
delete sourcesFromFunction[i];
this.addRequest(source);
}
sourcesFromFunction.length = 0;
} catch (e) {
const err = e as Error;
throw new Error(`Loading requests with sourcesFunction failed.\nCause: ${err.message}`);
}
}
}
/**
* @inheritDoc
*/
async persistState(): Promise<void> {
if (!this.#persistStateKey) {
throw new Error('Cannot persist state. options.persistStateKey is not set.');
}
if (this.isStatePersisted) return;
try {
this.#store ??= await KeyValueStore.open();
await this.#store.setValue(this.#persistStateKey, this.getState());
this.isStatePersisted = true;
} catch (e) {
const err = e as Error;
this.#log.exception(err, 'Attempted to persist state, but failed.');
}
}
/**
* Removes the `PERSIST_STATE` event listener registered during initialization and persists
* the current state one last time. Call this when you are done with the `RequestList` to avoid
* leaking the listener (and the requests it retains) on the shared event manager.
*/
async teardown(): Promise<void> {View on GitHub (pinned to dbe57fb09c)
Solutions
- Pass persistStateKey when creating the list: new RequestList({ sources, persistStateKey: 'my-state' })
- Or guard the call: only invoke persistState() when list has a configured key
- If state persistence is unwanted, remove the persistState() call rather than catching the error
Example fix
// before
const list = await RequestList.open('list', { sources });
await list.persistState(); // throws
// after
const list = await RequestList.open('list', { sources, persistStateKey: 'list-state', persistRequestsKey: 'list-reqs' });
await list.persistState(); Defensive patterns
Strategy: try-catch
Validate before calling
if (!list.persistStateKey && typeof list.persistState === 'function') {
// configure the key at construction instead of calling persistState
} Try / catch
try {
await list.persistState();
} catch (e) {
if (e.message.includes('persistStateKey is not set')) {
console.warn('State persistence skipped: no persistStateKey configured');
} else throw e;
} Prevention
- Always pass persistStateKey (and persistRequestsKey) when you intend to persist
- Only call persistState on lists constructed with a key
- Centralize list creation so the key is not forgotten
When it happens
Trigger: Calling list.persistState() (directly or via crawler.teardown / persistence hooks) on a RequestList constructed without a persistStateKey option.
Common situations: Adding periodic persistence to an existing list and forgetting the constructor option; calling crawlerTeardown/persist hooks generically for all storages while one list lacks the key.
Understand the failure class
Background: "Must pass :limit option" / "Missing required option" — required option errors explained — this error's family across 41 libraries.
Related errors
- At least one of "sources" or "sourcesFunction" must be provi
- The state object is not consistent with RequestList the orde
- The state object is not consistent with RequestList. Unknown
- The `minConcurrency`/`maxConcurrency`/`initialConcurrency`/`
- The `requestManager` option cannot be used in conjunction wi
AI-assisted analysis of apify/crawlee@dbe57fb09c (2026-08-30).
Data as JSON: /api/errors/f9291cbb09fa5390.
Report an issue: GitHub.