Error Handling

Build resilient real-time applications with comprehensive error handling strategies

Overview

Proper error handling is critical for building production-ready real-time applications. Network issues, permission denials, and API errors are inevitable—the difference between a great app and a frustrating one is how gracefully you handle these situations. BaxCloud SDK provides robust error detection and recovery mechanisms to help you build resilient applications.

Network Errors

Connection failures, timeouts, and reconnection handling

Permission Errors

Camera, microphone, and notification access denial

API Errors

Authentication failures, invalid tokens, and rate limits

Common Error Types

Understanding the errors you'll encounter when building with BaxCloud

Connection Errors

Network-related issues that prevent or interrupt the connection to BaxCloud servers.

  • CONNECTION_TIMEOUT - Server didn't respond within the timeout period
  • NETWORK_UNAVAILABLE - No internet connection available
  • CONNECTION_LOST - Connection dropped unexpectedly
  • RECONNECTION_FAILED - All reconnection attempts exhausted

Permission Errors

User denied access to required device capabilities.

  • CAMERA_PERMISSION_DENIED - User rejected camera access
  • MICROPHONE_PERMISSION_DENIED - User rejected microphone access
  • SCREEN_SHARE_DENIED - User cancelled screen sharing
  • NOTIFICATION_PERMISSION_DENIED - Push notifications blocked

Authentication Errors

Issues with API keys, tokens, or project credentials.

  • INVALID_API_KEY - API key is incorrect or malformed
  • TOKEN_EXPIRED - Access token has expired and needs refresh
  • UNAUTHORIZED - User doesn't have permission for this action
  • PROJECT_NOT_FOUND - Invalid project ID

Room Errors

Issues related to room access and capacity.

  • ROOM_NOT_FOUND - Specified room doesn't exist
  • ROOM_FULL - Room has reached maximum participant capacity
  • ROOM_LOCKED - Room is locked and requires invitation
  • PARTICIPANT_KICKED - User was removed from the room

Media Errors

Problems with accessing or using media devices.

  • DEVICE_NOT_FOUND - Requested camera or microphone not available
  • DEVICE_IN_USE - Device is being used by another application
  • UNSUPPORTED_FORMAT - Media format not supported on this device
  • TRACK_FAILED - Media track encountered an error

Basic Error Handling

Wrap all SDK calls in try/catch blocks to handle errors gracefully

The foundation of error handling is wrapping asynchronous SDK calls in try/catch blocks. This ensures errors don't crash your application and allows you to provide helpful feedback to users.

1import { BaxCloudClient } from '@baxcloud/react-sdk';
2import { useState } from 'react';
3
4export default function VideoCall() {
5  const [error, setError] = useState<string | null>(null);
6
7  const joinRoom = async () => {
8    const client = new BaxCloudClient({
9      projectId: 'your-project-id',
10      apiKey: 'your-api-key',
11    });
12
13    try {
14      await client.connect({
15        roomName: 'meeting-room',
16        liveType: 'video_call',
17        participant: {
18          userId: 'user-123',
19          name: 'John Doe',
20        },
21      });
22      
23      setError(null);
24      console.log('Successfully joined room');
25    } catch (error: any) {
26      console.error('Failed to join room:', error);
27      setError(error.message || 'Failed to connect');
28      
29      // Show user-friendly error message
30      alert('Unable to join the call. Please check your connection and try again.');
31    }
32  };
33
34  return (
35    <div>
36      {error && (
37        <div className="error-banner">
38          <AlertTriangle /> {error}
39        </div>
40      )}
41      <button onClick={joinRoom}>Join Call</button>
42    </div>
43  );
44}
đź’ˇ

Always Catch Errors

Every SDK method that performs network operations or device access can throw errors. Always wrap these calls in try/catch blocks to prevent unhandled exceptions from crashing your app.

Connection Error Handling

Handle network failures with retry logic and user feedback

Network issues are common in real-time applications. Implement retry logic with exponential backoff to automatically recover from temporary connection failures.

1import { BaxCloudClient } from '@baxcloud/react-sdk';
2import { useState } from 'react';
3
4const MAX_RETRIES = 3;
5const INITIAL_DELAY = 1000; // 1 second
6
7export default function ResilientConnection() {
8  const [isConnecting, setIsConnecting] = useState(false);
9  const [retryCount, setRetryCount] = useState(0);
10
11  const connectWithRetry = async (
12    client: BaxCloudClient,
13    retries = 0
14  ): Promise<void> => {
15    try {
16      setIsConnecting(true);
17      setRetryCount(retries);
18
19      await client.connect({
20        roomName: 'meeting-room',
21        liveType: 'video_call',
22        participant: {
23          userId: 'user-123',
24          name: 'John Doe',
25        },
26      });
27
28      setIsConnecting(false);
29      setRetryCount(0);
30      console.log('Connected successfully');
31    } catch (error: any) {
32      console.error(`Connection attempt ${retries + 1} failed:`, error);
33
34      if (retries < MAX_RETRIES) {
35        // Exponential backoff: 1s, 2s, 4s
36        const delay = INITIAL_DELAY * Math.pow(2, retries);
37        
38        console.log(`Retrying in ${delay / 1000} seconds...`);
39        await new Promise(resolve => setTimeout(resolve, delay));
40        
41        // Retry connection
42        return connectWithRetry(client, retries + 1);
43      } else {
44        setIsConnecting(false);
45        throw new Error('Failed to connect after multiple attempts');
46      }
47    }
48  };
49
50  const handleConnect = async () => {
51    const client = new BaxCloudClient({
52      projectId: 'your-project-id',
53      apiKey: 'your-api-key',
54    });
55
56    try {
57      await connectWithRetry(client);
58    } catch (error) {
59      alert('Unable to connect. Please check your internet connection.');
60    }
61  };
62
63  return (
64    <div>
65      <button onClick={handleConnect} disabled={isConnecting}>
66        {isConnecting ? `Connecting${retryCount > 0 ? ` (Retry ${retryCount}/${MAX_RETRIES})` : '...'}` : 'Join Call'}
67      </button>
68    </div>
69  );
70}
đź’ˇ

Exponential Backoff

Exponential backoff prevents overwhelming the server with rapid retry attempts. Each retry waits twice as long as the previous one: 1s, 2s, 4s, etc.

Permission Error Handling

Request permissions gracefully and handle denials

Camera and microphone permissions are essential for video calls. Always check permission status before attempting to access devices, and provide clear guidance when permissions are denied.

1import { BaxCloudClient } from '@baxcloud/react-sdk';
2import { useState } from 'react';
3
4export default function PermissionHandler() {
5  const [permissionError, setPermissionError] = useState<string | null>(null);
6
7  const requestPermissions = async () => {
8    try {
9      // Request camera and microphone access
10      const stream = await navigator.mediaDevices.getUserMedia({
11        video: true,
12        audio: true,
13      });
14      
15      // Stop tracks immediately - we just needed to request permission
16      stream.getTracks().forEach(track => track.stop());
17      
18      setPermissionError(null);
19      return true;
20    } catch (error: any) {
21      console.error('Permission denied:', error);
22      
23      if (error.name === 'NotAllowedError') {
24        setPermissionError('Camera and microphone access denied');
25        return false;
26      } else if (error.name === 'NotFoundError') {
27        setPermissionError('No camera or microphone found');
28        return false;
29      } else {
30        setPermissionError('Unable to access media devices');
31        return false;
32      }
33    }
34  };
35
36  const joinWithPermissions = async () => {
37    // Request permissions first
38    const hasPermissions = await requestPermissions();
39    if (!hasPermissions) {
40      alert('Please enable camera and microphone access in your browser settings.');
41      return;
42    }
43
44    // Now connect to room
45    const client = new BaxCloudClient({
46      projectId: 'your-project-id',
47      apiKey: 'your-api-key',
48    });
49
50    try {
51      await client.connect({
52        roomName: 'meeting-room',
53        liveType: 'video_call',
54        participant: { userId: 'user-123', name: 'John Doe' },
55      });
56
57      await client.enableCamera();
58      await client.enableMicrophone();
59    } catch (error: any) {
60      console.error('Failed to join:', error);
61      alert('Failed to join call: ' + error.message);
62    }
63  };
64
65  return (
66    <div>
67      {permissionError && (
68        <div className="error-banner">
69          <Lock /> {permissionError}
70          <button onClick={() => window.open('chrome://settings/content/camera')}>
71            Open Settings
72          </button>
73        </div>
74      )}
75      <button onClick={joinWithPermissions}>Join Call</button>
76    </div>
77  );
78}
⚠️

Request Early

Request permissions early in the user flow, not at the last moment. This gives users time to understand why permissions are needed and reduces friction when joining calls.

Media Device Errors

Handle device unavailability and fallback gracefully

Devices can become unavailable for various reasons: already in use, unplugged, or not found. Always handle these scenarios and provide fallback options.

1import { BaxCloudClient } from '@baxcloud/react-sdk';
2
3export default function DeviceErrorHandler() {
4  const handleCameraError = async (client: BaxCloudClient) => {
5    try {
6      await client.enableCamera();
7    } catch (error: any) {
8      console.error('Camera error:', error);
9
10      if (error.name === 'NotFoundError') {
11        alert('No camera found. You can join with audio only.');
12        // Continue without camera
13        await client.enableMicrophone();
14      } else if (error.name === 'NotReadableError') {
15        alert('Camera is being used by another application.');
16      } else {
17        alert('Unable to access camera: ' + error.message);
18      }
19    }
20  };
21
22  const handleMicrophoneError = async (client: BaxCloudClient) => {
23    try {
24      await client.enableMicrophone();
25    } catch (error: any) {
26      console.error('Microphone error:', error);
27
28      if (error.name === 'NotFoundError') {
29        alert('No microphone found. Joining as viewer only.');
30        // Continue without microphone
31      } else if (error.name === 'NotReadableError') {
32        alert('Microphone is being used by another application.');
33      } else {
34        alert('Unable to access microphone: ' + error.message);
35      }
36    }
37  };
38
39  const joinWithFallback = async () => {
40    const client = new BaxCloudClient({
41      projectId: 'your-project-id',
42      apiKey: 'your-api-key',
43    });
44
45    try {
46      await client.connect({
47        roomName: 'meeting-room',
48        liveType: 'video_call',
49        participant: { userId: 'user-123', name: 'John Doe' },
50      });
51
52      // Try to enable camera (with fallback)
53      await handleCameraError(client);
54
55      // Try to enable microphone (with fallback)
56      await handleMicrophoneError(client);
57    } catch (error) {
58      console.error('Failed to join:', error);
59    }
60  };
61
62  return <button onClick={joinWithFallback}>Join Call</button>;
63}
đź’ˇ

Graceful Degradation

Always provide fallback options. If the camera fails, join with audio only. If both fail, allow users to join as viewers. Never block access completely due to device errors.

Error Event Listeners

Monitor and respond to errors in real-time

BaxCloud SDK emits error events that you can listen to for proactive error handling and monitoring.

1import { BaxCloudClient } from '@baxcloud/react-sdk';
2import { useEffect } from 'react';
3
4export default function ErrorListeners() {
5  useEffect(() => {
6    const client = new BaxCloudClient({
7      projectId: 'your-project-id',
8      apiKey: 'your-api-key',
9    });
10
11    // Listen for connection failures
12    client.on('connectionFailed', (error) => {
13      console.error('Connection failed:', error);
14      showNotification('Connection lost. Attempting to reconnect...');
15    });
16
17    // Listen for reconnection success
18    client.on('reconnected', () => {
19      console.log('Reconnected successfully');
20      showNotification('Connection restored', 'success');
21    });
22
23    // Global error handler
24    client.on('error', (error) => {
25      console.error('SDK error:', error);
26      
27      // Log to analytics
28      logErrorToAnalytics({
29        type: error.type,
30        message: error.message,
31        timestamp: new Date().toISOString(),
32      });
33    });
34
35    return () => {
36      client.off('connectionFailed');
37      client.off('reconnected');
38      client.off('error');
39    };
40  }, []);
41
42  return <div>Video Call Interface</div>;
43}
đź’ˇ

Event-Driven Error Handling

Event listeners allow you to respond to errors proactively without waiting for method calls to fail. This is especially useful for detecting network issues before users notice them.

Retry Strategies

Implement smart retry logic for different scenarios

Different operations require different retry strategies. Here are common patterns for handling retries.

Exponential Backoff with Max Retries

Best for: Connection failures, API rate limits

1async function retryWithBackoff<T>(
2  operation: () => Promise<T>,
3  maxRetries = 3,
4  initialDelay = 1000
5): Promise<T> {
6  for (let i = 0; i < maxRetries; i++) {
7    try {
8      return await operation();
9    } catch (error) {
10      if (i === maxRetries - 1) throw error;
11      
12      const delay = initialDelay * Math.pow(2, i);
13      console.log(`Retry ${i + 1}/${maxRetries} in ${delay}ms`);
14      await new Promise(resolve => setTimeout(resolve, delay));
15    }
16  }
17  throw new Error('Max retries exceeded');
18}
19
20// Usage
21await retryWithBackoff(() => client.connect(options));

User-Initiated Retry

Best for: Permission errors, device selection

1import { useState } from 'react';
2
3export default function UserRetry() {
4  const [error, setError] = useState<string | null>(null);
5
6  const attemptConnection = async () => {
7    try {
8      setError(null);
9      await client.connect(options);
10    } catch (err: any) {
11      setError(err.message);
12    }
13  };
14
15  return (
16    <div>
17      {error && (
18        <div className="error-card">
19          <p>{error}</p>
20          <button onClick={attemptConnection}>Try Again</button>
21        </div>
22      )}
23    </div>
24  );
25}

Network-Aware Retry

Best for: Mobile apps with variable network conditions

1// React Native example
2import NetInfo from '@react-native-community/netinfo';
3
4async function retryWhenOnline(operation: () => Promise<void>) {
5  const state = await NetInfo.fetch();
6  
7  if (!state.isConnected) {
8    console.log('No internet. Waiting for connection...');
9    
10    // Wait for network to come back online
11    return new Promise((resolve, reject) => {
12      const unsubscribe = NetInfo.addEventListener(state => {
13        if (state.isConnected) {
14          unsubscribe();
15          operation().then(resolve).catch(reject);
16        }
17      });
18      
19      // Timeout after 30 seconds
20      setTimeout(() => {
21        unsubscribe();
22        reject(new Error('Network timeout'));
23      }, 30000);
24    });
25  }
26  
27  return operation();
28}
29
30// Usage
31await retryWhenOnline(() => client.connect(options));

Best Practices

Always wrap SDK calls in try/catch

Every method that performs async operations can throw errors. Wrapping calls prevents unhandled exceptions from crashing your app.

Provide clear error messages to users

Don't show technical error codes. Translate errors into user-friendly messages with actionable next steps: "Check your internet connection" or "Enable camera access".

Log errors for debugging

Send errors to your analytics or logging service. Include context like user ID, device type, and network conditions to help diagnose issues.

Test error scenarios

Simulate network failures, permission denials, and device errors during development. Use browser DevTools network throttling or test on poor networks.

Have fallback strategies

If camera fails, fallback to audio-only. If connection fails, allow offline mode or queue actions for later. Never leave users stuck.

Monitor error rates in production

Track error types and frequencies. A spike in connection errors might indicate a server issue, while many permission errors suggest UX problems.

Implement timeout handling

Don't let operations hang forever. Set reasonable timeouts (e.g., 10s for connection, 5s for device access) and show feedback to users.

Validate input before SDK calls

Check for empty room names, missing credentials, or invalid options before calling SDK methods. Catch errors early with better error messages.