Why doesn't my semver targeting rule match?
Last updated:
The value you are sending does not parse as a semantic version. An unparseable string matches nothing at all, with no fallback to text comparison, which is why the rule looks dead instead of behaving oddly. A leading v is fine and 2.0 compares equal to 2.0.0, but a build number like 1042 or a date will never satisfy a semver condition.
A semver condition parses both sides into version components before it compares anything. When the value from your evaluation context does not parse, the condition matches nothing at all. It never degrades into a plain string comparison. That is why the rule sits there inert rather than behaving strangely, and it accounts for most reports of a semver rule doing nothing.
What parses
The parser is fairly forgiving with real version strings.
// All of these parse{ app_version: '2.4.1' }{ app_version: 'v2.4.1' } // leading v is stripped{ app_version: '2.4' } // missing parts compare as 0, so this equals 2.4.0{ app_version: '2.4.1-beta' } // prereleases rank below the release{ app_version: '2.4.1+build7' } // build metadata is ignored for precedence
// These do not, and match nothing{ app_version: 1042 }{ app_version: '2026.08.06' } // parses, but as a version, not a date{ app_version: 'v2.4.1-rc.1 (build 90)' }Numeric parts get compared piece by piece, never as one long number, so 2.10.0 correctly ranks above 2.9.0. Version numbers of any size are safe.
A prerelease ranks below its release, which catches people out constantly: 2.4.1-beta does not satisfy βat least 2.4.1β even though it reads later. Build metadata is ignored entirely for precedence too, so 2.4.1+a and 2.4.1+b compare equal.
The usual causes
Mobile clients often send a build number where you wanted a version name, and the two live in different fields. A native app sending 1042 where you meant 2.4.1 produces exactly this symptom.
A version sent as a number when it should be a string is the other frequent one. So is a version string carrying anything beyond the version itself, since a suffix in parentheses fails the parse for the whole value.
Checking it
Read back the raw attribute for one user whose version should match, and confirm it is a string that would parse on its own. If it does parse and the rule still misses, check what sits above it, because rules run in priority order and the first match wins.
Server-side and local SDK evaluation share the same parser, so a version that matches in one matches in the other. No need to test both.
You will find the comparison operators listed in Targeting and segments. For building the rule itself, How to set up targeting rules has worked examples.
Related questions
Why did my targeting rule not match?
Rules run top to bottom and the first match wins, so an earlier rule can shadow the one you are testing. The other usual cause is a missing context attribute.
Why doesn't my segment match any users?
A rule pointing at a segment fails closed when the segment cannot resolve, so it matches nobody rather than everybody. How to tell that from a bad condition.
Why is my feature flag returning the wrong type?
SDKs do not coerce types. Asking for a boolean from a string flag returns the default you passed rather than converting, so code and dashboard disagree.
Still stuck?
The docs cover every SDK, and the free Solo plan is enough to reproduce most of these locally.