fix: coerce null variations + FBEvent Flow + per-flag isolation on sync - #12
Merged
Merged
Conversation
Three related resilience fixes surfaced by real-world testing against the
els.fluentinhealth.io FeatBit server.
1. coerceInputValues = true on both Json configs (StreamingJson +
FbApiClient.json). Server occasionally ships `"variation": null` in
streaming payloads for json-typed flags with an unset variation slot;
without coercion the whole payload fails to decode with
`Expected string value for a non-null key 'variation', got null literal`,
startTask never completes, and FBClient stays not-ready for its whole
lifetime. With coercion, null coerces to the property default ("")
and streaming proceeds.
2. Per-flag try/catch around store.upsert in both StreamingDataSynchronizer
and PollingDataSynchronizer.safePoll. If a single flag entry ever slips
past coercion (or throws for any other reason), we log-and-skip that
entry instead of aborting the whole batch. FBClient still becomes ready
with the surviving flags.
3. New FBClient.events(): Flow<FBEvent> API. Applications subscribe to
surface transport / decode failures (Ready, Reconnecting, SyncError,
TransportError) into their own observability stack (Sentry, Timber).
SyncError.recoverable disambiguates one-bad-flag-in-batch from a full
sync outage. README updated with the collector pattern.
Version bumped to 0.1.1-SNAPSHOT so consumers requesting this branch via
JitPack get a distinct artifact.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Devild007
force-pushed
the
fix/coerce-null-variation-and-events
branch
from
August 11, 2026 17:38
7af619a to
853515e
Compare
KaustubhNBhangre
approved these changes
Aug 11, 2026
lets-swapcode
approved these changes
Aug 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Three resilience fixes surfaced by real-world testing against a live FeatBit deployment.
coerceInputValues = trueon both Json configs (StreamingJson+FbApiClient.json).Server occasionally ships
"variation": nullin streaming payloads for json-typedflags with an unset variation slot. Without coercion the whole payload fails to decode
with
Expected string value for a non-null key 'variation', got null literal,startTasknever completes, andFBClientstays not-ready for its whole lifetime.With coercion, null coerces to the property default (
"") and streaming proceeds.Per-flag
try/catcharoundstore.upsertin bothStreamingDataSynchronizerandPollingDataSynchronizer.safePoll. If a single flag entry slips past coercion (or throwsfor any other reason), we log-and-skip that entry instead of aborting the whole batch.
FBClientstill becomes ready with the surviving flags.New
FBClient.events(): Flow<FBEvent>API. Applications subscribe to surfacetransport / decode failures (
Ready,Reconnecting,SyncError,TransportError) intotheir own observability stack (Sentry, Timber).
SyncError.recoverabledisambiguatesone-bad-flag-in-batch from a full sync outage. README updated with the collector pattern.
Version bumped to
0.1.1-SNAPSHOTso JitPack consumers requesting this branch get a distinctartifact.
Verification
./gradlew :featbit-client:build— green./gradlew test— greenbefore the fix,
FBClient failed to start within 5son every launch due to the nullvariation crash; after the fix,
FBClient successfully startedin ~0.6s and thedownstream Android app receives the expected flag variation string.
Test plan
coerceInputValuessemantics: null on a defaulted non-nullStringfield → property default rather than throw.FBEventshape matches expected observability surface (Timber /Sentry mapping shown in README).
v0.1.1after merge + tag.🤖 Generated with Claude Code