Why doesn't my semver targeting rule match?
Last updated:
Because the value you are sending does not parse as a semantic version. An unparseable string matches nothing rather than falling back 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. It never degrades into a plain string comparison, so the symptom is a rule that sits there inert instead of one behaving strangely.
That single behaviour explains most reports of a semver rule doing nothing.
What parses
The parser is deliberately tolerant of 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 are compared piece by piece instead of as one long number, so 2.10.0 correctly ranks above 2.9.0. Version numbers of any size are safe.
Two consequences catch people out. A prerelease ranks below its release, so 2.4.1-beta does not satisfy βat least 2.4.1β even though it reads later. And build metadata is ignored entirely for precedence, so 2.4.1+a and 2.4.1+b compare equal.
The usual causes
Mobile clients often send a build number rather than 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 instead of 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.
The same parsing rules apply to server-side and local SDK evaluation, so a version that matches in one will match in the other.
Operators are listed in Targeting and segments, with worked examples in How to set up targeting rules.
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.