{"record":{"id":"f4bf6c71911a616f","repo":"apify/crawlee","slug":"cannot-set-a-borrowed-ownedorinjected-value","errorCode":null,"errorMessage":"Cannot set() a borrowed OwnedOrInjected value","messagePattern":"Cannot set\\(\\) a borrowed OwnedOrInjected value","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/core/src/owned_or_injected.ts","lineNumber":92,"sourceCode":"    }\n\n    /**\n     * The resolved instance, or `undefined` when a lazily-filled owned slot hasn't been built yet. The non-throwing\n     * counterpart to {@apilink OwnedOrInjected.value|`value`} — pairs naturally with `?? fallback` so callers can read\n     * a possibly-empty slot without the `isPresent ? value : …` dance.\n     */\n    get maybeValue(): Injected | undefined {\n        return this.#present ? (this.#value as Injected) : undefined;\n    }\n\n    /**\n     * Fills the (owned) slot with the crawler-built default, returning it for convenience. Only valid on an owned,\n     * not-yet-filled slot: borrowed instances are never replaced and an owned slot is filled exactly once (re-setting\n     * would silently orphan the previous instance's lifecycle).\n     */\n    set(value: Owned): Owned {\n        if (!this.#owned) {\n            throw new Error('Cannot set() a borrowed OwnedOrInjected value');\n        }\n\n        if (this.#present) {\n            throw new Error('OwnedOrInjected value is already initialized');\n        }\n\n        this.#value = value;\n        this.#present = true;\n\n        return value;\n    }\n\n    /**\n     * Runs an owned-only lifecycle hook, invoked (with the value typed as the concrete `Owned`) only when the crawler\n     * owns a present instance — a no-op for a borrowed instance or an owned-but-not-yet-built slot.\n     */\n    async ifOwned<R>(fn: (value: Owned) => R | Promise<R>): Promise<R | undefined> {\n        if (!this.#owned || !this.#present) {","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/apify/crawlee/blob/dbe57fb09ca607ad59dcf998f3925ef9ac3bb26c/packages/core/src/owned_or_injected.ts#L74-L110","documentation":"set() fills an owned, not-yet-filled OwnedOrInjected slot with the crawler-built default. Borrowed (injected) slots are never replaced — the injected instance's lifecycle belongs to the caller — so calling set() on one throws.","triggerScenarios":"Calling slot.set(defaultInstance) on a slot that was constructed in 'borrowed' mode because the user injected their own instance through options.","commonSituations":"Library-internal lazy default creation running even though the user supplied a custom instance; custom code that obtains a slot from a configured crawler and tries to overwrite the injected dependency.","solutions":["Do not call set() when the user injected an instance; check `#owned`/ownership first or read the injected value instead.","Skip the default-creation step when `maybeValue` already holds an injected instance.","If you need a replaceable slot, construct the OwnedOrInjected as owned rather than borrowing an injected instance."],"exampleFix":"// before\nthis.clientSlot.set(createDefaultClient()); // throws when user injected one\n// after\nif (this.clientSlot.maybeValue == null) this.clientSlot.set(createDefaultClient());","handlingStrategy":"type-guard","validationCode":"if (slot.maybeValue != null || !slotIsOwned(slot)) {\n  // skip set(): injected or already filled\n} else {\n  slot.set(buildDefault());\n}","typeGuard":null,"tryCatchPattern":"try {\n  slot.set(defaultValue);\n} catch (err) {\n  if ((err as Error).message === 'Cannot set() a borrowed OwnedOrInjected value') {\n    // user injected their own instance; use it\n    return slot.value;\n  }\n  throw err;\n}","preventionTips":["Always check maybeValue before attempting set().","Treat injected instances as immutable — never overwrite them.","Gate lazy-default creation behind an ownership check.","Document which slots accept user injection."],"tags":["lifecycle","dependency-injection","initialization"],"backgroundTag":"cannot-set-borrowed-value","analyzedSha":"dbe57fb09ca607ad59dcf998f3925ef9ac3bb26c","analyzedAt":"2026-08-30T22:22:28.328Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}