apify/crawlee · error · Error

At least one of "sources" or "sourcesFunction" must be provi

Error message

At least one of "sources" or "sourcesFunction" must be provided.

What it means

A RequestList must be given its URLs either statically via the sources array or dynamically via sourcesFunction. Constructing one with neither would produce an always-empty list, so the constructor validates and throws immediately.

Source

Thrown at packages/core/src/storages/request_list.ts:333

    /**
     * To create new instance of `RequestList` we need to use `RequestList.open()` factory method.
     * @param options All `RequestList` configuration options
     * @internal
     */
    private constructor(options: RequestListOptions = {}) {
        const {
            sources,
            sourcesFunction,
            persistStateKey,
            persistRequestsKey,
            state,
            proxyConfiguration,
            keepDuplicateUrls,
            httpClient,
        } = parseArgument(options, requestListOptionsSchema);

        if (!(sources || sourcesFunction)) {
            throw new Error('At least one of "sources" or "sourcesFunction" must be provided.');
        }

        this.#persistStateKey = persistStateKey ? `CRAWLEE_${persistStateKey}` : persistStateKey;
        this.#persistRequestsKey = persistRequestsKey ? `CRAWLEE_${persistRequestsKey}` : persistRequestsKey;
        this.#initialState = state;
        this.#httpClient = httpClient;

        // If this option is set then all requests will get a pre-generated unique ID and duplicate URLs will be kept in the list.
        this.#keepDuplicateUrls = keepDuplicateUrls;

        // Will be empty after initialization to save memory.
        this.#sources = sources ? [...sources] : [];
        this.#sourcesFunction = sourcesFunction;

        // The proxy configuration used for `requestsFromUrl` requests.
        this.#proxyConfiguration = proxyConfiguration;

        this.persistState = this.persistState.bind(this);

View on GitHub (pinned to dbe57fb09c)

Solutions

  1. Pass sources: new RequestList({ sources: ['https://example.com'] })
  2. Or pass sourcesFunction: () => fetchUrls() to generate sources at initialize() time
  3. If requests are added manually later, use RequestQueue instead of RequestList

Example fix

// before
const list = await RequestList.open('list', {});
// after
const list = await RequestList.open('list', { sources: ['https://example.com'] });
Defensive patterns

Strategy: validation

Validate before calling

function assertRequestListOptions(options) {
  if (!options.sources && !options.sourcesFunction) {
    throw new TypeError('RequestList needs "sources" or "sourcesFunction"');
  }
}
assertRequestListOptions({ sources: config.urls });

Type guard

const hasSources = (o) => Array.isArray(o?.sources) && o.sources.length > 0 || typeof o?.sourcesFunction === 'function';

Prevention

When it happens

Trigger: new RequestList({ sources: undefined, sourcesFunction: undefined }) — e.g. both options omitted, misspelled (source/sources), or computed as undefined by a ternary/config lookup.

Common situations: Loading source config from env/JSON that came back empty and was assigned verbatim; renaming options during a refactor; copying an example and deleting both fields while intending to addRequest() later.

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


AI-assisted analysis of apify/crawlee@dbe57fb09c (2026-08-30). Data as JSON: /api/errors/6d3a8687c9a174a8. Report an issue: GitHub.