fix: Call identify hooks during init.#487
Conversation
| flagStore.replaceStore(newStoredItems: cachedFlags) | ||
| } | ||
|
|
||
| let hookState = executeBeforeIdentifyHooks(context: context) |
There was a problem hiding this comment.
The beforeIdentify hooks should run after the auto environment attributes are added to the context (so that the implementer of the beforeIdentify call can see all the added attributes), and before we use that modified context to load cache or make network connections.
https://github.com/launchdarkly/sdk-specs/tree/main/specs/HOOK-hooks#conditional-requirement-1412
So likely it needs to be called right after this block, but double check.
if config.autoEnvAttributes {
context = AutoEnvContextModifier(environmentReporter: environmentReporter, logger: config.logger).modifyContext(context)
}
You can think of "identify" as updating the context the SDK is going to use and do things with. If the SDK does anything with the context that can be detected or observed by the outside world, such as making network requests or loading cache which impacts flag evals, and it does so before beforeIdentify, it has sorta violated the logical order and it is a externally detectable contradiction of the API.
There was a problem hiding this comment.
Okay, I think I've got it, and I think that's the right place. I mean, it seems clear from the spec that beforeIdentify should be called before flagCache.getCachedData at least. It's not obvious on first glance whether the various make functions on the previous lines have side effects, so it's better to err on calling the hooks before them.
There was one slight complication -- Swift really does not like init methods calling member functions before all object properties have been initialized, and flagSynchronizer is initialized after the cache is loaded. But the code in executeBeforeIdentifyHooks is very short and doesn't access any properties other than hooks, so I copy-pasted the code into init.
Please take another look.
There was a problem hiding this comment.
Did the commit get pushed?
There was a problem hiding this comment.
🤦♀️ no. okay. it's been pushed now. sorry about that.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
🤖 I have created a release *beep* *boop* --- ## [11.1.2](11.1.1...11.1.2) (2026-03-24) ### Bug Fixes * app hang in didEnterBackground by making ConnectionInformationStore writes async ([#489](#489)) ([72b0ab4](72b0ab4)) * Call identify hooks during init. ([#487](#487)) ([844d5d4](844d5d4)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low risk release bookkeeping only: version strings and documentation/changelog updates with no functional code changes in this diff. > > **Overview** > Bumps the SDK version from `11.1.1` to `11.1.2` across release metadata (`.release-please-manifest.json`), build settings (`DYLIB_CURRENT_VERSION`/`MARKETING_VERSION` in `project.pbxproj`), CocoaPods (`LaunchDarkly.podspec`), and runtime reporting (`ReportingConsts.sdkVersion`). > > Updates `CHANGELOG.md` with the `11.1.2` release notes and refreshes the SPM install snippet in `README.md` to reference `11.1.2`. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit feb3392. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: LaunchDarklyReleaseBot <LaunchDarklyReleaseBot@launchdarkly.com>

Requirements
Related issues
N/A
Describe the solution you've provided
Before this change,
beforeIdentifyandafterIdentifywere only called whenidentifywas called. After this change, they are also called as part ofinit.Describe alternatives you've considered
None.
Additional context
I don't think this would be considered a breaking change, but I wouldn't mind a second opinion. The change in behavior is observable by the user, but the new behavior is what was originally intended. So I would consider this a bugfix, and would not expect customers to need to make any changes to their code to deal with the change.
Note
Medium Risk
Changes observable hook execution timing by invoking
beforeIdentify/afterIdentifyduringLDClientinit and by including plugin-provided hooks in that lifecycle, which could affect apps with side-effecting hooks. Scope is limited to hook plumbing and tests, with no auth or data model changes.Overview
LDClientnow executes identify hooks as part of initialization: it runsbeforeIdentifywith method name"init"and defersafterIdentifyuntil the initialsetOnlinecompletes.Plugin hooks are collected earlier (during
LDClientinit rather thanLDClient.start) so plugin-provided hooks participate in the init identify lifecycle, and the hook helper APIs inLDClientIdentifyHook.swiftare widened tointernalto support this.Tests are updated/expanded to assert the additional init-time hook calls, preserve hook ordering, and verify plugin hooks fire during init.
Written by Cursor Bugbot for commit ab0372a. This will update automatically on new commits. Configure here.