Skip to content

feat!: DISABLED is a successful evaluation (still defaults)#671

Merged
toddbaert merged 6 commits into
mainfrom
feat/disabled-flag-reason
Jun 2, 2026
Merged

feat!: DISABLED is a successful evaluation (still defaults)#671
toddbaert merged 6 commits into
mainfrom
feat/disabled-flag-reason

Conversation

@jonathannorris

@jonathannorris jonathannorris commented May 25, 2026

Copy link
Copy Markdown
Member
  • Disabled flags now resolve successfully with reason=DISABLED instead of errorCode=FLAG_NOT_FOUND. See the ADR.
  • Breaking, but barely: resolved values are unchanged (the caller-provided default is still surfaced).
  • The break is only observable for consumers that inspect reason / errorCode on disabled-flag evaluations.

Related Issues

Closes #653
Part of open-feature/flagd#1965


Warning

This PR depends on #673 (RPC flagd-selector header wiring) merging first; the cross-flagset disabled scenario in the RPC e2e suite will fail until that lands. All other RPC e2e + in-process scenarios pass.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request modifies the JsonEvaluator in the flagd provider to return a ResolutionDetails object with a Reason.Disabled status instead of throwing a FeatureProviderException when a flag is disabled. The corresponding unit tests have been updated to verify that evaluating a disabled flag returns the correct default value, a disabled reason, and a null variant, even when targeting rules are present. There are no review comments to address.

@jonathannorris

jonathannorris commented May 25, 2026

Copy link
Copy Markdown
Member Author

Note on why we return defaultValue rather than null for disabled flags, tagging @suthar26 and @toddbaert since this touches the ADR intent.

The Java provider (open-feature/java-sdk-contrib#1800) returns null for the value field, and the Java SDK substitutes the caller's code default when it sees null. That's the cleanest implementation of the ADR's "omit value, SDK uses code default" intent.

We can't do the same in .NET. The provider interface uses non-nullable value types:

Task<ResolutionDetails<bool>> ResolveBooleanValueAsync(string key, bool defaultValue, ...)
//                                                                  ^^^^ can't be null

bool, int, and double are value types; they always have a value. There's no Optional<bool> in the contract. The .NET SDK also doesn't have fallback logic for this case: defaultValue is only substituted on exception, not on a successful resolution with default(T). If we returned default(bool) (false) and the caller passed true as their default, they'd get false back.

Go has the same constraint (GenericResolutionDetail[bool]) and Go providers handle it the same way, returning defaultValue when the flag is disabled.

The correct fix would be adding substitution logic to the .NET SDK itself (when reason=DISABLED, use defaultValue), but that's a separate change. Until then, returning defaultValue from the provider achieves the same end result for the caller.

@toddbaert toddbaert changed the title feat(flagd): in-process evaluator returns DISABLED reason for disabled flags feat(flagd)!: DISABLED is a successful evaluation (still defaults) Jun 1, 2026
@toddbaert toddbaert changed the title feat(flagd)!: DISABLED is a successful evaluation (still defaults) feat!: DISABLED is a successful evaluation (still defaults) Jun 1, 2026
@toddbaert toddbaert marked this pull request as ready for review June 1, 2026 18:48
@toddbaert toddbaert requested review from a team as code owners June 1, 2026 18:48
@toddbaert toddbaert force-pushed the feat/disabled-flag-reason branch from c7d1d77 to 7504696 Compare June 1, 2026 19:01
jonathannorris and others added 5 commits June 1, 2026 15:51
…d flags

Signed-off-by: Jonathan Norris <jonathan.norris@dynatrace.com>
Signed-off-by: Jonathan Norris <jonathan.norris@dynatrace.com>
Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
@toddbaert toddbaert force-pushed the feat/disabled-flag-reason branch from 7504696 to 88ffaf7 Compare June 1, 2026 19:51
@toddbaert toddbaert merged commit 7d3665b into main Jun 2, 2026
11 checks passed
@toddbaert toddbaert deleted the feat/disabled-flag-reason branch June 2, 2026 17:02
This was referenced Jun 16, 2026
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.

feat: flagd provider in-process mode returns reason=DISABLED for disabled flags

7 participants