… service
matchFeatureFlagProperty returned false for every operator outside
is_not/is_set when the property was null. The flags service matches null
as the string "null" for the string operators
(rust/feature-flags property_matching.rs, to_string_representation), as
the sdk-specs local-feature-flag-evaluator requires, so negated operators
disagreed: not_icontains, not_starts_with, not_ends_with and not_regex on
null returned false where the service returns true, and icontains "nul"
and regex "^nu" missed a match.
icontains, not_icontains, starts_with, not_starts_with, ends_with,
not_ends_with, regex and not_regex now pass the null guard; the existing
string helpers already stringify null as "null". Numeric, date and semver
operators keep returning false for null, which the service also does.
Problem
Local flag evaluation in
@posthog/corereturnedfalsefor every operator exceptis_notandis_setwhen the property value wasnull. The flags service matchesnullas the string"null"for string operators (rust/feature-flags/src/properties/property_matching.rs,to_string_representation), and the sdk-specslocal-feature-flag-evaluatorspec requires the same canonical stringification. So local and remote evaluation disagreed for an explicitnullproperty:not_icontainsxnot_starts_withxnot_ends_withxnot_regexxicontainsnulregex^nuChanges
icontains,not_icontains,starts_with,not_starts_with,ends_with,not_ends_with,regexandnot_regexnow pass the null guard. The existing string helpers already turnnullinto"null", so no other logic changed. Numeric, date and semver operators still returnfalsefornull, which matches the service.@posthog/convexevaluates through the samematchFeatureFlagProperty, so it gets the fix too.Release info Sub-libraries affected
Libraries affected
Checklist
If releasing new changes
pnpm changesetto generate a changeset file🤖 Agent context
Autonomy: Human-driven (agent-assisted). DRI: @quotentiroler (an outside contributor can't be set as assignee).
rust/feature-flags. Every expected value in the new test was checked against that matcher.node:22container on a fresh clone:featureFlagLocalEvaluation.spec.tspasses (116 tests),tsc --noEmitand oxlint are clean, and oxfmt 0.65 reports no changes. With the fix reverted, the 6 divergent cases fail. The full core suite's only failures aresrc/traces/index.spec.tsRetry-After timing tests, which also fail on unpatched main in the same environment.pnpm changesetformat.Maintainer follow-up
The PR commits have been signed without changing their contents or original authorship. Latest
mainwas merged without rewriting history. Separate test-only commits update the three Node assertions and two Convex assertions that still expected the old null behavior and remove their stale null-guard comments. The null guard now consults one list containingexact,is_notand the eight string/regex operators. The redundantis_setentry and separate equality exceptions have been removed without changing behavior.Verified on Node 24.18.1 after building the workspace dependencies:
pnpm --filter posthog-node test:unit --coverage.enabled=false: 1,166 tests passed.pnpm --filter posthog-node test:edge-compat: 1,166 tests passed.pnpm --filter @posthog/convex test:unit: 198 tests passed.git diff --checkpassed.origin/mainfound no actionable issues atfc21b21dedfa21cd3e8d394e5ab54de17d94e895.This is API-compatible, but explicit-null local flag decisions can change. Missing properties and
undefinedretain their existing behavior.Related ports of the same fix: