diff --git a/openfeature-provider/pom.xml b/openfeature-provider/pom.xml
index 924aa3c..25893dc 100644
--- a/openfeature-provider/pom.xml
+++ b/openfeature-provider/pom.xml
@@ -4,7 +4,7 @@
com.mixpanel
mixpanel-java-openfeature
- 0.1.1
+ 0.2.0
jar
Mixpanel Java SDK - OpenFeature Provider
@@ -126,7 +126,13 @@
com.mixpanel
mixpanel-java
- 1.8.0
+
+ 1.10.0
diff --git a/openfeature-provider/src/main/java/com/mixpanel/openfeature/MixpanelProvider.java b/openfeature-provider/src/main/java/com/mixpanel/openfeature/MixpanelProvider.java
index 251eea9..5cf3615 100644
--- a/openfeature-provider/src/main/java/com/mixpanel/openfeature/MixpanelProvider.java
+++ b/openfeature-provider/src/main/java/com/mixpanel/openfeature/MixpanelProvider.java
@@ -4,6 +4,7 @@
import com.mixpanel.mixpanelapi.featureflags.config.LocalFlagsConfig;
import com.mixpanel.mixpanelapi.featureflags.config.RemoteFlagsConfig;
import com.mixpanel.mixpanelapi.featureflags.model.SelectedVariant;
+import com.mixpanel.mixpanelapi.featureflags.model.Source;
import com.mixpanel.mixpanelapi.featureflags.provider.BaseFlagsProvider;
import com.mixpanel.mixpanelapi.featureflags.provider.LocalFlagsProvider;
import dev.openfeature.sdk.*;
@@ -131,8 +132,14 @@ private ProviderEvaluation evaluate(String key, T defaultValue, Evaluatio
return errorResult(defaultValue, ErrorCode.GENERAL, e.getMessage());
}
- if (result.isFallback()) {
- return errorResult(defaultValue, ErrorCode.FLAG_NOT_FOUND, "Flag not found: " + key);
+ // A fallback source means the SDK had no real variant to serve.
+ // The reason discriminates why (flag missing, context key missing,
+ // no rollout matched, backend error) so we translate each to the
+ // OpenFeature error the spec assigns to it instead of collapsing
+ // every fallback to FLAG_NOT_FOUND.
+ Source source = result.getSource();
+ if (source instanceof Source.Fallback) {
+ return mapFallback(((Source.Fallback) source).reason, key, defaultValue);
}
T value = mapper.apply(result);
@@ -144,12 +151,44 @@ private ProviderEvaluation evaluate(String key, T defaultValue, Evaluatio
return successResult(value, result.getVariantKey());
}
+ private ProviderEvaluation mapFallback(Source.Fallback.Reason reason, String flagKey, T defaultValue) {
+ switch (reason) {
+ case FLAG_NOT_FOUND:
+ return errorResult(defaultValue, ErrorCode.FLAG_NOT_FOUND, "Flag not found: " + flagKey);
+ case MISSING_CONTEXT_KEY:
+ return errorResult(defaultValue, ErrorCode.TARGETING_KEY_MISSING,
+ "Missing targeting key for flag: " + flagKey);
+ case NO_ROLLOUT_MATCH:
+ // Flag exists but no rollout matched — per the OpenFeature spec
+ // this is DEFAULT with no error, distinct from FLAG_NOT_FOUND.
+ return defaultResult(defaultValue);
+ case BACKEND_ERROR:
+ return errorResult(defaultValue, ErrorCode.GENERAL,
+ "Backend error evaluating flag: " + flagKey);
+ default:
+ // Fail closed on unrecognized reasons so a new value added to
+ // the base SDK enum without wiring here doesn't silently
+ // produce a successful-looking evaluation.
+ return errorResult(defaultValue, ErrorCode.GENERAL,
+ "Unrecognized fallback reason " + reason + " for flag: " + flagKey);
+ }
+ }
+
+ private ProviderEvaluation defaultResult(T defaultValue) {
+ return ProviderEvaluation.builder()
+ .value(defaultValue)
+ .reason("DEFAULT")
+ .build();
+ }
+
private SelectedVariant