apify/crawlee · error · TypeError
Cannot set property '${String(prop)}' on serviceLocator dire
Error message
Cannot set property '${String(prop)}' on serviceLocator directly. Use the setter methods (e.g. setConfiguration(), setStorageBackend()) instead. What it means
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()).
Source
Thrown at packages/core/src/service_locator.ts:401
serviceLocatorStorage.enterWith(serviceLocator);
},
exitScope: () => {
serviceLocatorStorage.enterWith(previousStore as any); // casting to any so that `undefined` is accepted - this "unsets" the AsyncLocalStorage
},
};
}
export const serviceLocator = new Proxy({} as ServiceLocatorInterface, {
get(_target, prop) {
const active = serviceLocatorStorage.getStore() ?? globalServiceLocator;
const value = Reflect.get(active, prop, active);
if (typeof value === 'function') {
return value.bind(active);
}
return value;
},
set(_target, prop) {
throw new TypeError(
`Cannot set property '${String(prop)}' on serviceLocator directly. Use the setter methods (e.g. setConfiguration(), setStorageBackend()) instead.`,
);
},
});
View on GitHub (pinned to dbe57fb09c)
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.
Example fix
// before serviceLocator.configuration = new Configuration(); // after serviceLocator.setConfiguration(new Configuration());
Defensive patterns
Strategy: type-guard
Validate before calling
if (!Object.isFrozen(Object.getPrototypeOf(serviceLocator))) { /* ok to read */ }
// always register via:
// typeof serviceLocator.setConfiguration === 'function' Type guard
function canRegisterService(locator: unknown): locator is { setConfiguration: (c: Configuration) => void } {
return typeof locator === 'object' && locator !== null &&
typeof (locator as any).setConfiguration === 'function';
} Try / catch
try {
(serviceLocator as any).anything = 1;
} catch (e) {
if (e instanceof TypeError && /serviceLocator directly/.test(e.message)) {
serviceLocator.setConfiguration(cfg); // use setters
} else throw e;
} Prevention
- 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.
When it happens
Trigger: Any code doing serviceLocator.someService = x, serviceLocator['#logger'] = y, Object.assign(serviceLocator, {...}), or a transpiled/test framework writing onto the locator object.
Common situations: 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.
Related errors
- ${this.getMessageFromError(error)}
- Invalid "proxyUrl". Unsupported protocol: ${proxyUrl}.
- Invalid "proxyUrl" option: authentication is only supported
- A new page can be created with provided context only when us
- Configuration is immutable. Pass options via the constructor
AI-assisted analysis of apify/crawlee@dbe57fb09c (2026-08-30).
Data as JSON: /api/errors/6f7c00ae4742d257.
Report an issue: GitHub.