{"record":{"id":"6f7c00ae4742d257","repo":"apify/crawlee","slug":"cannot-set-property-string-prop-on-servicelo","errorCode":null,"errorMessage":"Cannot set property '${String(prop)}' on serviceLocator directly. Use the setter methods (e.g. setConfiguration(), setStorageBackend()) instead.","messagePattern":"Cannot set property '(.+?)' on serviceLocator directly\\. Use the setter methods \\(e\\.g\\. setConfiguration\\(\\), setStorageBackend\\(\\)\\) instead\\.","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/core/src/service_locator.ts","lineNumber":401,"sourceCode":"            serviceLocatorStorage.enterWith(serviceLocator);\n        },\n        exitScope: () => {\n            serviceLocatorStorage.enterWith(previousStore as any); // casting to any so that `undefined` is accepted - this \"unsets\" the AsyncLocalStorage\n        },\n    };\n}\n\nexport const serviceLocator = new Proxy({} as ServiceLocatorInterface, {\n    get(_target, prop) {\n        const active = serviceLocatorStorage.getStore() ?? globalServiceLocator;\n        const value = Reflect.get(active, prop, active);\n        if (typeof value === 'function') {\n            return value.bind(active);\n        }\n        return value;\n    },\n    set(_target, prop) {\n        throw new TypeError(\n            `Cannot set property '${String(prop)}' on serviceLocator directly. Use the setter methods (e.g. setConfiguration(), setStorageBackend()) instead.`,\n        );\n    },\n});\n","sourceCodeStart":383,"sourceCodeEnd":406,"githubUrl":"https://github.com/apify/crawlee/blob/dbe57fb09ca607ad59dcf998f3925ef9ac3bb26c/packages/core/src/service_locator.ts#L383-L406","documentation":"The serviceLocator export is wrapped in a Proxy whose set trap throws a TypeError for any direct property assignment. Service registration is intentionally write-protected; it must go through the typed setter methods (setConfiguration(), setStorageBackend(), setEventManager(), setLogger()).","triggerScenarios":"Any code doing serviceLocator.someService = x, serviceLocator['#logger'] = y, Object.assign(serviceLocator, {...}), or a transpiled/test framework writing onto the locator object.","commonSituations":"Trying to monkey-patch the locator in tests, naive dependency injection via assignment, or code migrated from an older version where the locator was a plain object.","solutions":["Replace direct assignment with the corresponding setter method (setConfiguration(), setEventManager(), setStorageBackend(), setLogger()).","Read services via getConfiguration(), getLogger(), etc., or through the proxy's get trap, which returns bound methods.","Never mutate the locator object; construct a new ServiceLocator for different wiring.","In tests, use dependency injection via constructor options (serviceLocator) instead of patching the global locator."],"exampleFix":"// before\nserviceLocator.configuration = new Configuration();\n\n// after\nserviceLocator.setConfiguration(new Configuration());","handlingStrategy":"type-guard","validationCode":"if (!Object.isFrozen(Object.getPrototypeOf(serviceLocator))) { /* ok to read */ }\n// always register via:\n// typeof serviceLocator.setConfiguration === 'function'","typeGuard":"function canRegisterService(locator: unknown): locator is { setConfiguration: (c: Configuration) => void } {\n    return typeof locator === 'object' && locator !== null &&\n        typeof (locator as any).setConfiguration === 'function';\n}","tryCatchPattern":"try {\n    (serviceLocator as any).anything = 1;\n} catch (e) {\n    if (e instanceof TypeError && /serviceLocator directly/.test(e.message)) {\n        serviceLocator.setConfiguration(cfg); // use setters\n    } else throw e;\n}","preventionTips":["Treat serviceLocator as read-only; only call its setter/getter methods.","Avoid Object.assign or spread mutation of the locator.","Use constructor/serviceLocator options for dependency injection in tests."],"tags":["proxy","immutability","dependency-injection"],"backgroundTag":"readonly-object-assignment","analyzedSha":"dbe57fb09ca607ad59dcf998f3925ef9ac3bb26c","analyzedAt":"2026-08-30T22:22:28.328Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}