apify/crawlee · error · ServiceConflictError

ServiceConflictError('EventManager', eventManager…

Error message

ServiceConflictError('EventManager', eventManager, this.#eventManager)

What it means

setEventManager() throws ServiceConflictError if a different EventManager instance is registered when one already exists in the ServiceLocator. This guards the singleton invariant: all components must share one EventManager so events route consistently.

Solutions

  1. Register your custom EventManager before anything else initializes the default one.
  2. Reuse the existing event manager (getEventManager()) instead of constructing a new one.
  3. Only call setEventManager() once per locator lifetime.
  4. Reset/recreate the ServiceLocator between test cases that each set their own event manager.

Example fix

// before
const crawler = new CheerioCrawler(...); // initializes default EventManager
locator.setEventManager(myEventManager); // throws

// after
const locator = new ServiceLocator();
locator.setEventManager(myEventManager); // before any retrieval
const crawler = new CheerioCrawler({ ..., serviceLocator: locator });
Defensive patterns

Strategy: validation

Validate before calling

let existing;
try { existing = locator.getEventManager(); } catch { existing = null; }
if (existing && existing !== myEventManager) { /* skip registration */ }

Try / catch

try {
    locator.setEventManager(em);
} catch (e) {
    if (e instanceof ServiceConflictError) em = locator.getEventManager();
    else throw e;
}

Prevention

When it happens

Trigger: Calling setEventManager(emA), then setEventManager(emB) with a different EventManager instance; or retrieving the event manager first and later trying to inject a custom one.

Common situations: Manually wiring a custom EventManager after crawlee already initialized one (e.g. by creating a crawler or accessing events), or double initialization in tests/HMR.

Related errors


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

Appendix: source

Thrown at packages/core/src/service_locator.ts:229

                this.getLogger().warning(
                    'Implicit creation of event manager will implicitly set configuration as side effect. ' +
                        'It is advised to explicitly first set the configuration instead.',
                );
            }
            this.#eventManager = LocalEventManager.fromConfiguration(this.getConfiguration());
        }
        return this.#eventManager;
    }

    setEventManager(eventManager: EventManager): void {
        // Same instance, no need to do anything
        if (this.#eventManager === eventManager) {
            return;
        }

        // Already have a different event manager that was retrieved
        if (this.#eventManager) {
            throw new ServiceConflictError('EventManager', eventManager, this.#eventManager);
        }

        this.#eventManager = eventManager;
    }

    getStorageBackend(): StorageBackend {
        if (!this.#storageBackend) {
            this.getLogger().debug(
                'No storage backend set, implicitly creating and using the default storage backend ' +
                    '(FileSystemStorageBackend when persistStorage is enabled, MemoryStorageBackend otherwise).',
            );
            if (!this.#configuration) {
                this.getLogger().warning(
                    'Implicit creation of storage backend will implicitly set configuration as side effect. ' +
                        'It is advised to explicitly first set the configuration instead.',
                );
            }
            const configuration = this.getConfiguration();

View on GitHub (pinned to dbe57fb09c)