SDKC++ SDK

Diagnostics & errors

Device status, automatic connection recovery and error handling.

Current version · 1.4.0

Diagnostics & errors

Read first: Debug logs (turn on logs before reproducing the problem) · What you get: read device status, automatic connection recovery and error types

To locate a symptom, see Common questions; this chapter covers the tools for reading device status and handling errors.

Status and diagnostics

device.status() returns ReadChannel<GloveStatus>. Common fields include connected, stale, timestamp, last_error, reconnect_count, and fields. Subscribe to status when continuous monitoring is needed; use latest() when only the current value matters. For the complete fields, see GloveStatus.

Automatic connection recovery

Automatic recovery applies only to a source that was successfully started and then disconnected unexpectedly; a first-run connection failure is returned synchronously by start(). During recovery, only the affected source becomes connected=false, stale=true and reports the reason through last_error, while other sources keep running. After identity confirmation, recovery makes it connected=true again, clears last_error, and increments reconnect_count. If it was already start()ed before the recovery and data is received again, stale=false; a source that has not been start()ed keeps stale=true after reconnecting until it starts receiving current data.

Rendering diagram

Sending haptics or other device commands while disconnected fails immediately with a not-connected error; they are not queued and not replayed. The current haptic setting is cleared; after recovery it must be set again by the application. Explicitly calling stop() or close() cancels recovery. For the same identity-confirmed device, retargeting output that is already ready and still valid can continue to be used after recovery and is not recalibrated merely because of the reconnection.

sdk.health() returns the aggregate status of the entire SDK, and glove.health() returns the status of all configured gloves. To judge whether the runtime is healthy, read and record the running health before the stop request:

const auto running_health = glove.health();
std::cout << "running health ok=" << running_health.ok << '\n';

Health includes:

  • ok: whether it is currently healthy.
  • warning_count and error_count: cumulative diagnostic counts.
  • devices: the connection, staleness, and error state of each source.
  • last_error: summary of the most recent error.
  • runtime_overrun: whether any runtime task overrun has been observed.
  • topic_callback_error: indicates callback errors recorded during SDK data processing. In C++, an exception thrown by the callback passed to subscribe() does not escape the callback boundary and does not set topic_callback_error; to observe it, record or handle it inside the callback.

After actively stopping and waiting for the run loop to finish, you can read the stopped lifecycle health again before closing to confirm the connected/stale lifecycle state of the devices. After telemetry stops, devices enter stale=true, so even with warning_count=0 and error_count=0, the aggregate value may still be ok=false. This is the expected stopped lifecycle state; it does not indicate a runtime failure and does not change the meaning of the shared Health.ok. For the complete sequence, see foreground_runtime.cpp and background_runtime.cpp. For the complete returned fields, see Health.

Error handling

Catch the most specific exception type for the failure scenario, and prefer the structured information provided by the exception:

ExceptionTypical meaning
InvalidArgumentErrorThe configuration, frame, haptics, or call parameters are invalid
ClosedHandleErrorThe SDK or Glove is already closed
StaleUpdateErrorThe update result has been consumed or is no longer valid
LifecycleErrorThe lifecycle order or run mode does not allow the current operation
UnavailableFeatureErrorThe current device, platform, or delivery does not support this capability
CommandRejectedErrorThe control command was rejected
GloveControlErrorThe device control command failed: not connected, device busy, timed out; the reason is in kind (GloveControlErrorKind)
InternalErrorThe SDK cannot continue the operation
PanicErrorAn unexpected runtime failure

Device or target selection additionally has NotFoundSelectionError and AmbiguousSelectionError, both carrying structured selector and candidate information. Asynchronous wait cancellation uses the standard std::system_error(std::errc::operation_canceled).

Catch exceptions by specific recovery strategy, then use QnBotError as the final SDK error boundary:

try {
    auto device = glove.device("primary");
} catch (const qnbot::NotFoundSelectionError& error) {
    for (const auto& candidate : error.candidates()) {
        std::cerr << candidate << '\n';
    }
} catch (const qnbot::QnBotError& error) {
    std::cerr << error.what() << '\n';
}