onError
Optional callback prop on <BTProvider>. Fires whenever the underlying BLE stack or the SDK's characteristic parser encounters a failure that should be surfaced to your app.
Signature
import type { BleError } from "react-native-ble-plx";
import type { DeviceData } from "@ovok/native";
export interface ErrorCallback {
deviceData?: DeviceData;
error: BleError | Error | string;
}
onError?: (data: ErrorCallback) => void;
deviceData is undefined for errors raised before a device is identified (e.g. the BLE adapter is off, the OS revoked permission mid-scan). Once a known device is matched, subsequent errors carry the DeviceData of the device they relate to.
When it fires
| Trigger | deviceData | error shape |
|---|---|---|
| BLE adapter powered off | undefined | BleError with errorCode: BluetoothLE |
| Permission revoked mid-scan | undefined | BleError, message includes "permission" |
| Scan throttling by OS | undefined | BleError, message includes "scan" |
| Device disconnected unexpectedly during a measurement | the device that dropped | BleError, message includes "disconnect" |
| Characteristic parser failed to decode a frame | the device that emitted it | Error with a parser-specific message |
| Pairing failure | the device that failed to pair | BleError |
| App-level violation (e.g. invalid measurement type for device) | the device | string |
The union of BleError | Error | string means you cannot assume .message exists. Always narrow:
function asMessage(e: BleError | Error | string): string {
return typeof e === "string" ? e : e.message;
}
Usage
import React, { useCallback } from "react";
import { Alert } from "react-native";
import { BTProvider } from "@ovok/native";
function MyApp() {
const handleError = useCallback((data) => {
const message = typeof data.error === "string" ? data.error : data.error.message;
if (message.toLowerCase().includes("permission")) {
Alert.alert(
"Bluetooth Permission Needed",
"Please grant Bluetooth and Location permissions in Settings.",
);
return;
}
if (message.toLowerCase().includes("disconnect")) {
// Transient — let the user retry. The SDK will re-scan automatically.
console.warn(
`Device ${data.deviceData?.name ?? "unknown"} disconnected:`,
message,
);
return;
}
// Anything else — surface it.
Alert.alert("Bluetooth Error", message);
}, []);
return (
<BTProvider /* ...other props */ onError={handleError}>
<YourScreens />
</BTProvider>
);
}
Don't confuse with DeviceStatus.Error
There is no DeviceStatus.Error value — the DeviceStatus enum has only 4 values. "Error" is purely a UI label your app derives from onError firing. If you want the rest of your code to treat errors as a status, mirror them into your own state machine:
const [uiStatus, setUiStatus] = useState<UILabel>("idle");
const handleError = useCallback((data) => {
setUiStatus("error");
}, []);
const handleDeviceStatusChanged = useCallback((data) => {
// Map the 4 SDK values to your richer UI labels here.
}, []);
Recovery
There is no automatic retry. After onError fires:
- Permission failures → drive
permissionFallbackUI viaonAccessPermissionChanged. - Transient disconnects → no action; the provider keeps scanning, and the next advertisement re-fires
onDeviceFound. - Parser failures → safe to ignore one frame; if they repeat, the device firmware may have a different revision than the SDK expects (file an issue with the device model + firmware version).
Related
- BTProvider — full provider reference
- on-device-status-changed — the canonical 4-value DeviceStatus enum
- on-access-permission-changed — permission-specific error handling