Skip to content

FFL-1878: Fix stale state context mismatch#3224

Merged
sameerank merged 2 commits into
developfrom
sameerank/FFL-1878/fix-stale-state-context-mismatch
Mar 13, 2026
Merged

FFL-1878: Fix stale state context mismatch#3224
sameerank merged 2 commits into
developfrom
sameerank/FFL-1878/fix-stale-state-context-mismatch

Conversation

@sameerank

@sameerank sameerank commented Mar 5, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Fixes a bug where the Flags SDK would transition to Stale state when a network request fails, without checking if the cached context matches the requested context. This could result in serving flags from a different user/context.

Changes:

  1. EvaluationsManager.kt: Added context comparison before transitioning to Stale state. If contexts don't match, transitions to Error instead.
  2. FlagsClientState.kt: Simplified NotReady state documentation to remove incorrect claim about flag availability.

Motivation

When setEvaluationContext() fails due to a network error, the SDK was transitioning to Stale state if any cached flags existed, without verifying the cached context matched the requested context. This could cause:

  • Scenario 1: User A's cached flags being served to User B on a fresh app open
  • Scenario 2: User A's flags being served to User B after a mid-session user switch

This fix aligns the Android SDK behavior with the iOS SDK implementation.

Additional Notes

  • Added unit tests for both matching and mismatched context scenarios
  • The fix follows the same pattern implemented in the iOS SDK (FlagsRepository.swift)

Fixes: FFL-1878

Review checklist (to be filled by reviewers)

  • Feature or bugfix MUST have appropriate tests (unit, integration, e2e)
  • Make sure you discussed the feature or bugfix with the maintaining team in an Issue
  • Make sure each commit and the PR mention the Issue number (cf the CONTRIBUTING doc)

@sameerank
sameerank force-pushed the sameerank/FFL-1878/fix-stale-state-context-mismatch branch from e864065 to 942f9ed Compare March 5, 2026 03:45
@datadog-datadog-prod-us1-2

This comment has been minimized.

*
* This state occurs:
* - Before the first [setEvaluationContext()] call (initialization)
* - After client shutdown

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see a shutdown method, so if we want to keep this comment here, it would help to point instead to a specific function or code path. The closest thing I could find is Datadog.stopInstance()

* - After client shutdown
* - When the provider is not initialized or unavailable
*
* No flags are available for evaluation in this state.

@sameerank sameerank Mar 5, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not quite true. There may be cached flags available

Provider readiness checks if there's an evaluation context (which may be cached) and doesn't check the client's state

iOS does something similar in checking the cached context, but there is a difference in behaviors

Scenario iOS Android
Fresh install, NotReady state context = nil → PROVIDER_NOT_READY Same
App restart with cached data, NotReady state context = cached → flags work Same
After reset() context = nil → PROVIDER_NOT_READY N/A (no reset method)

iOS has a reset() which clears data and sets state to notReady. Android doesn't have this method.

// Only use cached flags if they match the requested context to avoid
// serving flags from a different user/context.
val cachedContextMatches = flagsRepository.getEvaluationContext() == context
if (hadFlags && cachedContextMatches) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fixes the state transition logic if there's a network error when requesting flags for a context (User B). It's only safe to serve "stale" flags if the requested context matches the cached context

Cached Flags Cached Context Requested Context State
None - User B Error
Exist User A User A Stale
Exist User A User B Error ✓ (was incorrectly Stale)

Assuming User B should never see User A's flags

@sameerank
sameerank requested a review from typotter March 5, 2026 04:14
@codecov-commenter

codecov-commenter commented Mar 5, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 71.35%. Comparing base (79caf0b) to head (41107ad).

Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #3224      +/-   ##
===========================================
- Coverage    71.42%   71.35%   -0.07%     
===========================================
  Files          940      940              
  Lines        34764    34765       +1     
  Branches      5894     5894              
===========================================
- Hits         24828    24806      -22     
- Misses        8288     8317      +29     
+ Partials      1648     1642       -6     
Files with missing lines Coverage Δ
...id/flags/internal/evaluation/EvaluationsManager.kt 88.10% <100.00%> (+0.29%) ⬆️
...om/datadog/android/flags/model/FlagsClientState.kt 83.33% <ø> (ø)

... and 40 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@sameerank
sameerank force-pushed the sameerank/FFL-1878/fix-stale-state-context-mismatch branch from 942f9ed to 08a17b8 Compare March 5, 2026 05:08
@sameerank
sameerank force-pushed the sameerank/FFL-1878/fix-stale-state-context-mismatch branch from 08a17b8 to 41107ad Compare March 13, 2026 00:59
@sameerank
sameerank marked this pull request as ready for review March 13, 2026 01:52
@sameerank
sameerank requested review from a team as code owners March 13, 2026 01:52
@gh-worker-ownership-write-b05516
gh-worker-ownership-write-b05516 Bot removed the request for review from typotter March 13, 2026 07:54
@sameerank
sameerank merged commit d31130d into develop Mar 13, 2026
26 checks passed
@sameerank
sameerank deleted the sameerank/FFL-1878/fix-stale-state-context-mismatch branch March 13, 2026 15:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants