fix: stop publishing unsupported tracking values as 0 - #77
Open
vahidlazio wants to merge 1 commit into
Open
Conversation
Dart wraps a value it has no Confidence type for — a DateTime, a null, a
custom object — as {'type': 'unknown', 'value': value.toString()}, so the
stringified value does reach native. Both native sides then threw it away.
iOS convertValue's default branch returned ConfidenceValue(integer: 0), so
track('my_event', {'ts': DateTime.now()}) published ts = 0. The event was
accepted, so nothing surfaced the corruption; the data was simply wrong.
Android convert() threw IllegalArgumentException("Unknown type unknown")
instead. Since Dart's track is fire-and-forget, that surfaced only as a
logged handler error while the event was lost — a different failure from
iOS for the same input.
Both now publish the string Dart already computed, so the two platforms
agree and the caller's value survives. Stringifying is preferred over
rejecting (track must not throw at the app) and over omitting the key
(silent loss is the failure being fixed). The unrecognised-type branches
are hardened the same way rather than left to coerce.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The defect
Dart wraps a value it has no Confidence type for — a
DateTime, anull, a custom object — as{'type': 'unknown', 'value': value.toString()}. The stringified value does reach native. Both native sides then discarded it, differently:convertValue/convertbehaviourdefault:returnsConfidenceValue.init(integer: 0)0else ->throwsIllegalArgumentException("Unknown type unknown")So
track('my_event', {'ts': DateTime.now()})publishests = 0on iOS. The event is accepted, so nothing surfaces the corruption — the data is just wrong. On Android the same input takes a different path: because Dart'strackis fire-and-forget, the throw surfaces only as a logged handler error while the event is dropped.Two platforms, same input, two different wrong outcomes.
The fix
Both sides now publish the string Dart already computed, so they agree and the caller's value survives. The unrecognised-type branches are hardened the same way rather than left to coerce, and iOS logs when it hits one.
Why stringify rather than the alternatives:
trackmust not throw at the application (see fix: always reply to track method channel calls and surface failures #75, which made exactly that guarantee for the reply path)."2026-09-07 12:34:56.000Z"rather than0or nothing.A
nullbecomes the string"null". That is deliberate: it is visible and truthful about what the caller passed, where0was neither.Testing
The native halves cannot be exercised from Dart, and this repo's Kotlin unit tests are not run by CI (the
android-testjob runsflutter driveon an emulator, not./gradlew testDebugUnitTest). The added Dart tests therefore pin the wire format the native fix depends on.Verified falsifiable — coercing the
unknownbranch to0fails withExpected: '2026-09-07 12:34:56.000Z' / Actual: <0>andExpected: not <0> / Actual: <0>.flutter analyzeclean (one pre-existingexample/.envasset warning, created by CI) andflutter test5/5 passing.Scope
Pre-existing on
mainand independent of #75 (track/flushreply paths) and #76 (async reply safety).🤖 Generated with Claude Code