Surfaces
| Surface | When |
|---|---|
| Synchronous exception | API misuse before/around session boundaries. |
null returned from a query | Optional state not available (e.g. getCurrentStats() outside a session). |
| Empty event stream | Permissions denied or consentBehavior = false. |
| Silent drops at the runtime gate | Behavior consent is not granted in the Synheart runtime. |
| Native channel errors | Method-channel failures bubble as PlatformException (Dart) / typed errors (Kotlin/Swift). |
Synchronous exceptions
The Dart SDK throws standardStateError / ArgumentError for misuse:
| Cause | Exception |
|---|---|
startSession() before initialize() | StateError("SynheartBehavior not initialized"). |
startSession() while another session is active | The SDK rolls the previous session and starts a new one (no exception). |
BehaviorSession.end() after the session has already ended | Returns the cached summary; safe to call multiple times. |
calculateMetricsForTimeRange with start > end or out of session bounds | ArgumentError. |
dispose() followed by any further API call | StateError("SynheartBehavior disposed"). |
IllegalStateException and IllegalArgumentException; Swift uses Swift’s standard precondition failures with descriptive messages.
Permission failures
The SDK does not throw when a platform permission is missing. Instead:| Permission | Behavior when denied |
|---|---|
| Notification listener (Android) | notification events do not flow. BehaviorSessionSummary.notificationSummary.notificationCount = 0. |
| Phone / call log (Android) | call events do not flow. notificationSummary.callCount = 0. |
| Accelerometer | Motion-lite stays unloaded; motionState = null in the summary. onMotionSample stream emits no samples. |
checkNotificationPermission()/requestNotificationPermission()(Android).checkCallPermission()/requestCallPermission()(Android).
Native channel errors
Method-channel calls can fail if the native plugin isn’t registered (e.g. desktop builds without the platform layer). Dart’sPlatformException:
| Code | Cause | Recovery |
|---|---|---|
MissingPluginException | Native side not registered | Verify plugin registration and platform-specific build steps. |
INITIALIZATION_FAILED | Native init threw | Inspect details; usually a permissions or platform-version issue. |
INVALID_CONFIG | Config field rejected by native | Validate config; surface to developer. |
Motion classifier errors
WhenenableMotionLite = true and the bundled ONNX model fails to load:
- The failure is logged with the underlying ORT error.
motionStatestaysnullfor the session.getCurrentStats()does not include motion-state fields.onEventand other behavioral metrics continue normally.
initialize() after dispose()) to retry.
Runtime gate drops
When the host wires the SDK intosynheart-core → the Synheart runtime, behavior events pass through the runtime’s consent gate. If Behavior consent is not granted, the runtime drops events at the engine seam silently. The SDK sees no error — events fire on onEvent, but the runtime never persists or aggregates them.
This is intentional: SDK-side telemetry remains coherent (UIs still see live events) while the privacy boundary is enforced past the SDK.
Validation invariants
The SDK guarantees, regardless of error state:- Numeric metrics are always finite and within their declared range (NaN/inf clamped to
0.0). BehaviorSessionSummaryis always emitted onsession.end(), even when no events flowed.BehaviorEvent.eventIdis unique within a session.BehaviorEvent.timestampis ISO-8601 UTC.
Related
- Behavior Overview — config flags that gate each surface.
- Threat Model — what’s collected and what’s not.
- Metric Definitions — numerical stability rules.
- Consent System — runtime-side
Behaviorgate.