Flagsmith / Flagsmith/flagsmith

Race condition in FeatureSegment priority assignment allows duplicate priorities

Open
#6,858 1 comment 0 reactions 0 assignees View on GitHub
api
Dominant language
Python
Stars
6.6k
Forks
567
Avg merge
1d 13h
Merged PRs (30d)
121

Description

Concurrent `POST /environments/{env_key}/features/{feature_id}/create-segment-override/` requests for the same feature+environment can produce `FeatureSegment` rows with duplicate `priority` values.

## Root cause

`FeatureSegment` inherits from `ordered_model.OrderedModelBase`. On `save()`, if `priority is None`, it calls `get_next_order()` which does `max(priority) + 1` scoped to `(feature, environment, environment_feature_version)`.

This read-then-write is not atomic — when two requests arrive concurrently, both can read the same `max(priority)` and assign the same value.

## Impact

Duplicate priorities break the contract that segment override priority is a total order. Downstream consumers (e.g. the flag engine evaluator) use strict `<` to pick the winning segment override when priorities tie, making the result depend on iteration order rather than intentional priority.

## Reproduction

Call `create-segment-override` concurrently for 3 different segments on the same feature+environment (e.g. with 32 parallel workers). Observe that two or more `FeatureSegment` rows end up with `priority=0`.

## Suggested fix

Either:
1. Use `select_for_update()` / row-level locking around the `get_next_order()` + `save()` sequence, or
2. Add a unique constraint on `(feature, environment, environment_feature_version, priority)` and retry on conflict.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.