Skip to content

fix: tolerate duplicate flag keys in data sync payload - #33

Open
dmytrodanilenkov wants to merge 1 commit into
featbit:masterfrom
dmytrodanilenkov:fix/duplicate-flag-key
Open

dmytrodanilenkov wants to merge 1 commit into
featbit:masterfrom
dmytrodanilenkov:fix/duplicate-flag-key

Conversation

@dmytrodanilenkov

@dmytrodanilenkov dmytrodanilenkov commented Nov 10, 2026 •

Copy link
Copy Markdown

Fixes #32

DataModel.Data.toStorageType() built an ImmutableMap keyed by flag key, so a payload with the same key twice (e.g. featbit-agent still holding an archived copy of a flag that was deleted and re-created) threw "Multiple entries with same key" and failed the whole sync, leaving new clients in a reconnect loop.

Collect items into a LinkedHashMap so the last entry wins, as the Go, Python, Rust, Ruby and Node SDKs already do.

RetriggerView in GreptileConfidence Score: 5/5

This PR appears safe to merge.

Summary

The PR lets data sync accept repeated flag keys and segment IDs instead of throwing an exception.

  • Data sync keeps the last item when a payload repeats a key.

Reviews (1) · Last reviewed commit: "fix: tolerate duplicate flag keys in dat..." · Reviewed by Greptile

Summary by CodeRabbit

  • Bug Fixes
    • Feature flags and segments with duplicate identifiers now consistently retain the last entry provided. Active entries are preserved when they follow archived copies, and stored configuration no longer reflects an earlier duplicate.

DataModel.Data.toStorageType() built an ImmutableMap keyed by flag key,
so a payload with the same key twice (e.g. featbit-agent still holding
an archived copy of a flag that was deleted and re-created) threw
"Multiple entries with same key" and failed the whole sync, leaving new
clients in a reconnect loop.

Collect items into a LinkedHashMap so the last entry wins, as the Go,
Python, Rust, Ruby and Node SDKs already do.
@coderabbitai

coderabbitai Bot commented Nov 10, 2026 •

Copy link
Copy Markdown

Explain Change →

No actionable comments were generated in the recent review.

Walkthrough

Data.toStorageType() now uses insertion-ordered maps keyed by item ID. When IDs repeat, the last feature flag or segment entry is retained. Tests cover duplicate and distinct feature flag IDs.

Changes: Storage conversion

Layer / File(s) Summary
Duplicate-ID handling
src/main/java/co/featbit/server/DataModel.java, src/test/java/co/featbit/server/DataModelTest.java
Data.toStorageType() uses last-entry-wins maps for feature flags and segments, then copies the maps to immutable maps. Tests cover archived and live flags with the same ID, duplicate archived flags, and distinct IDs.

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix · Severity of issue fixed: Medium

Possibly related issues

  • featbit/featbit-java-sdk#32: The change addresses the reported full-sync failure caused by an archived and live flag with the same key.

Suggested reviewers: dsun0720

Merge Risk: Minimal · up to 1f20a

Data sync payloads with duplicate flag keys no longer fail the whole sync. The last entry for each key is kept, consistent with other FeatBit SDKs. No concrete merge-blocking risk was found.

Pre-merge checks: Passed 5

Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly summarizes the main change: handling duplicate flag keys in data sync payloads.
Docstring Coverage Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentat…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 1 functions across 2 files.

Finishing Touches

Generate unit tests (beta)

  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

Recent review info

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 2925d75b-73ca-4580-88a6-4c2ed69d5b4a
Commits

Reviewing files that changed from the base of the PR and between 4741389 and 1f20ae8.

Files selected for processing: 2

  • src/main/java/co/featbit/server/DataModel.java
  • src/test/java/co/featbit/server/DataModelTest.java

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

This branch has not been deployed

No deployments
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.

Full sync fails when payload contains an archived and live flag with same key

1 participant