Documentation Index
Fetch the complete documentation index at: https://docs.synheart.ai/llms.txt
Use this file to discover all available pages before exploring further.
The behavior SDK has a small, mostly-quiet error surface. Most “failures” manifest as zero-valued metrics or empty event streams rather than thrown exceptions — by design, since the SDK is consent-gated and may run inside hosts that haven’t granted permissions yet.
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 standard StateError / 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"). |
The Kotlin SDK uses 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. |
Hosts query availability via:
checkNotificationPermission() / requestNotificationPermission() (Android).
checkCallPermission() / requestCallPermission() (Android).
iOS doesn’t have user-facing permissions for the surfaces the SDK uses; silent fallback is the same.
Native channel errors
Method-channel calls can fail if the native plugin isn’t registered (e.g. desktop builds without the platform layer). Dart’s PlatformException:
| 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. |
Kotlin and Swift surface these as their own typed errors at the Kotlin / Swift bridge.
Motion classifier errors
When enableMotionLite = true and the bundled ONNX model fails to load:
- The failure is logged with the underlying ORT error.
motionState stays null for the session.
getCurrentStats() does not include motion-state fields.
onEvent and other behavioral metrics continue normally.
The SDK does not retry model loading mid-session; restart the session (or initialize() after dispose()) to retry.
Runtime gate drops
When the host wires the SDK into synheart-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).
BehaviorSessionSummary is always emitted on session.end(), even when no events flowed.
BehaviorEvent.eventId is unique within a session.
BehaviorEvent.timestamp is ISO-8601 UTC.
If any of these break, file a bug.