> ## 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.

# Errors

> Permission failures, lifecycle errors, and the runtime-gate drop semantics

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.

## Related

* [Behavior Overview](/synheart-behavior/overview) — config flags that gate each surface.
* [Threat Model](/synheart-behavior/threat-model) — what's collected and what's not.
* [Metric Definitions](/synheart-behavior/metric-definitions) — numerical stability rules.
* [Consent System](/synheart-core/consent-system) — runtime-side `Behavior` gate.
