Reliability and Error Handling
Client-side SDKs can run in browsers and mobile apps where networks, storage, and signed-definition verification can fail temporarily. The SDKs are designed to keep feature evaluation predictable while making those failures visible.
Server-side SDKs follow the same contract for snapshot/cache and signature failures — see Server-side reliability (shared overview; language-specific APIs are under each SDK).
Shared behavior
The client-side SDKs follow the same reliability contract where the platform supports the equivalent feature:
onErrorreports fetch, cache, storage, parse, signature, and JWK failures.- The last error is stored before
onErrorruns, so synchronous error state likelastError,state.error, or debug output is up to date in the callback. - After one successful load, refresh failures preserve the last-known-good flags instead of clearing UI state.
- Fallback/default/empty flags are not written over persistent cache just because a transient fetch or parse failed.
- Non-empty feature gates fail closed when no valid flag map is available.
- Feature UI components subscribe to effective flag changes, so interval, WebSocket sync messages, identity, local-gate, and fallback transitions can re-render.
Error callback signatures
Most JavaScript-family SDKs expose the same callback shape:
onError?: (message: string, error?: unknown) => void
Flutter includes the Dart stack trace when available:
onError: (String message, Object? error, StackTrace? stackTrace) {
// Report to your monitoring provider
}
React Native provider callbacks receive an Error instance:
<TogglyProvider
onError={(error) => {
// Report to your monitoring provider
}}
>
<App />
</TogglyProvider>
What to report
Use onError for operational visibility rather than control flow. Good targets
include Sentry, Crashlytics, Datadog, LogRocket, or your app logger.
onError: (message, error) => {
logger.warn('Toggly SDK error', { message, error })
}
The callback can fire when:
- the definitions endpoint is unavailable;
- a response cannot be parsed;
- signed definitions cannot be verified;
- JWKs cannot be fetched or do not contain the expected key;
- local storage/cache reads or writes fail;
- a refresh listener or hook throws.
It does not mean a flag is enabled or disabled. Evaluate features through the
normal Feature component, hook, directive, or evaluateFeatureGate API.
Last-known-good fallback
When a refresh fails after flags were already loaded, the SDK keeps evaluating
against the previous effective flags and reports the failure through onError
or error state. This prevents a temporary network or signature problem from
unexpectedly hiding gated UI that was already visible.
On the first load, if no valid cache exists, the SDK falls back to configured
defaults when provided. Treat defaults as a safety net, not as a replacement for
monitoring onError.
UI updates after refresh
React, Angular, Vue, Svelte, Astro, Gatsby, Next, Nuxt, Remix, Flutter, and React Native feature UI now subscribe to effective flag changes where those SDKs provide reactive UI. Timer refreshes, WebSocket sync signals, identity changes, and local-gate changes can update rendered content without requiring a page reload or app restart.
When the WebSocket sends sync with unchanged: true, SDKs skip an HTTP round-trip.
See WebSocket sync.
For custom UI built directly on the service/client object, prefer the SDK's
reactive hook/store/directive/component. If you need lower-level subscriptions,
use APIs such as subscribeFeaturesRefresh or React Native's
effectiveFlagsChanged event when available.
Docusaurus edge behavior
The Docusaurus edge worker does not expose an application onError callback,
but it follows the cache portion of the same contract. Transient flag or
manifest fetch failures do not overwrite a last-known-good manifest or cache
with {}. That keeps edge stripping and page gating from converting a temporary
fetch failure into broad false/404 behavior.
On a cold start, when no prior successful fetch has populated edge or in-memory cache yet, the worker still returns an empty flag map until the first successful load. Treat that as a separate bootstrap case from refresh-time last-known-good fallback.