{"record":{"id":"4f2628e01d846c09","repo":"apify/crawlee","slug":"serviceconflicterror-logger-logger-this-logge","errorCode":null,"errorMessage":"ServiceConflictError('Logger', logger, this.#logger)","messagePattern":"ServiceConflictError\\('Logger', logger, this\\.#logger\\)","errorType":"exception","errorClass":"ServiceConflictError","httpStatus":null,"severity":"error","filePath":"packages/core/src/service_locator.ts","lineNumber":287,"sourceCode":"        }\n\n        this.#storageBackend = storageBackend;\n    }\n\n    getLogger(): CrawleeLogger {\n        if (!this.#logger) {\n            this.#logger = new ApifyLogAdapter(log);\n        }\n        return this.#logger;\n    }\n\n    setLogger(logger: CrawleeLogger): void {\n        if (this.#logger === logger) {\n            return;\n        }\n\n        if (this.#logger) {\n            throw new ServiceConflictError('Logger', logger, this.#logger);\n        }\n\n        this.#logger = logger;\n    }\n\n    getChildLog(prefix: string): CrawleeLogger {\n        return this.getLogger().child({ prefix });\n    }\n\n    getStorageInstanceManager(): StorageInstanceManager {\n        if (!ServiceLocator.#storageInstanceManager) {\n            ServiceLocator.#storageInstanceManager = new StorageInstanceManager();\n        }\n        return ServiceLocator.#storageInstanceManager;\n    }\n\n    reset(): void {\n        this.#configuration = undefined;","sourceCodeStart":269,"sourceCodeEnd":305,"githubUrl":"https://github.com/apify/crawlee/blob/dbe57fb09ca607ad59dcf998f3925ef9ac3bb26c/packages/core/src/service_locator.ts#L269-L305","documentation":"setLogger() throws ServiceConflictError if a different CrawleeLogger is registered after one already exists in the ServiceLocator. The library assumes a single logger instance so all components emit logs through the same sink.","triggerScenarios":"Calling setLogger(loggerA) then setLogger(loggerB); or using the default logger implicitly and later trying to inject a custom logger via the locator.","commonSituations":"Installing a custom log implementation after crawlee initialization, or in tests where multiple setups each register a logger on the shared locator.","solutions":["Inject the custom logger before any crawlee component initializes (before crawler construction or storage access).","Reuse getLogger() and wrap/extend it rather than replacing it.","Call setLogger() only once per ServiceLocator lifetime.","Prefer configuring log level via Log.getLogLevel()/log options rather than swapping logger instances."],"exampleFix":"// before\nconst crawler = new PlaywrightCrawler(...); // default logger registered\nlocator.setLogger(myLogger); // throws\n\n// after\nconst locator = new ServiceLocator();\nlocator.setLogger(myLogger);\nconst crawler = new PlaywrightCrawler({ ..., serviceLocator: locator });","handlingStrategy":"validation","validationCode":"let existing;\ntry { existing = locator.getLogger(); } catch { existing = null; }\nif (existing && existing !== myLogger) { /* logger already registered */ }","typeGuard":null,"tryCatchPattern":"try {\n    locator.setLogger(logger);\n} catch (e) {\n    if (e instanceof ServiceConflictError) {\n        const base = locator.getLogger();\n        logger = Object.assign(Object.create(Object.getPrototypeOf(base)), logger);\n    } else throw e;\n}","preventionTips":["Register the logger in the same bootstrap step as other services, before crawlers run.","Extend the existing logger (child logger) rather than replacing it.","Adjust log levels via configuration instead of swapping instances."],"tags":["logging","dependency-injection","lifecycle"],"backgroundTag":"service-already-configured","analyzedSha":"dbe57fb09ca607ad59dcf998f3925ef9ac3bb26c","analyzedAt":"2026-08-30T22:22:28.328Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}