How to Handle Reconnection and Errors Gracefully
Handle disconnect events, connection and send failures, retries, and offline UI with a safe application-owned reconnection policy.
8 min read
DNotifier SDKs surface connection failures, send errors, and disconnect events through thrown exceptions and onDisconnected callbacks. The SDK does not auto-reconnect — your app owns retry policy and offline UX.
Common Error Sources
| Phase | Error | Typical cause |
|---|---|---|
| connect() | Thrown exception | Wrong secret, invalid appId, plan issue, or network failure |
| send() / sendBinary() | Not connected | Called before connect() or after disconnect |
| send() | Validation error | Missing senderId, receiverId, or receiverIds |
| Transport | onDisconnected | Network loss, server close, or explicit disconnect() |
Handle Disconnects
Register onDisconnected when constructing the client:
JavaScript / TypeScript
const notifier = new DNotifier({
// ...
onDisconnected: ({ code, reason }) => {
console.log("Disconnected:", code, reason);
showOfflineBanner();
scheduleReconnect();
},
});Dart
onDisconnected: ({code, reason}) {
print('Disconnected: $code $reason');
showOfflineBanner();
scheduleReconnect();
},Reconnection Pattern
Always call connect() again after a disconnect. Do not call send() while isConnected is false.
JavaScript / TypeScript
let reconnectTimer = null;
function scheduleReconnect() {
if (reconnectTimer) return;
reconnectTimer = setTimeout(async () => {
reconnectTimer = null;
try {
await notifier.connect();
hideOfflineBanner();
} catch (err) {
console.error("Reconnect failed:", err.message);
scheduleReconnect(); // exponential backoff recommended
}
}, 3000);
}Dart
Future<void> reconnectWithBackoff(DNotifier notifier) async {
for (var attempt = 1; attempt <= 5; attempt++) {
try {
await notifier.connect();
return;
} catch (e) {
await Future.delayed(Duration(seconds: attempt * 2));
}
}
}Send Error Handling
try {
await notifier.send({
senderId: myUserId,
receiverId: peerUserId,
data: { type: "text", text: "Hello" },
});
} catch (err) {
if (err.message === "Not connected") {
await notifier.connect();
// Retry once after the connection succeeds.
} else {
showSendFailedToast(err.message);
}
}Auth Failures at Connect
try {
await notifier.connect();
} catch (err) {
if (err.message.includes("401") || err.message.includes("auth")) {
promptReLogin(); // Refresh credentials from your backend.
} else {
showNetworkError();
}
}Chunk Reassembly Failures
If the connection drops while a large message is chunking:
- Partial chunks are discarded on the receiver.
- The sender should retry the full send() after reconnecting.
- Consider showing "Message failed to send" in the chat UI with a retry button.
Explicit Disconnect
notifier.disconnect();
// isConnected === false; onDisconnected firesUse an explicit disconnect when the user logs out or your app tears down the realtime session.
Production Checklist
- Listen to onDisconnected — update the UI and pause sends.
- Use exponential backoff — avoid hammering authentication on flaky networks.
- Load history idempotently — after reconnecting, call fetchChatHistory to fill gaps.
- Deduplicate by metadata.id if your app retries sends.