Documentation Index
Fetch the complete documentation index at: https://developers.telnyx.com/llms.txt
Use this file to discover all available pages before exploring further.
Error Handling
Common errors, debugging techniques, and troubleshooting guide for the Telnyx React Native SDK.
Authentication Errors
Invalid Credentials
Error: AUTH_FAILED or INVALID_CREDENTIALS
Symptoms: Login fails with credential-based authentication.
Solutions:
import { createCredentialConfig } from '@telnyx/react-voice-commons-sdk';
const handleAuthError = async (voipClient, username, password) => {
try {
const config = createCredentialConfig(username, password, {
debug: true, // Enable debug logging
});
await voipClient.login(config);
} catch (error) {
if (error.code === 'AUTH_FAILED') {
console.error('Invalid credentials provided');
// Show user-friendly error message
Alert.alert('Login Failed', 'Please check your username and password');
} else if (error.code === 'NETWORK_ERROR') {
console.error('Network connection failed');
// Retry logic or offline handling
}
}
};
Token Validation Errors
Error: INVALID_TOKEN or TOKEN_EXPIRED
Symptoms: JWT token authentication fails.
Solutions:
import { createTokenConfig } from '@telnyx/react-voice-commons-sdk';
const handleTokenAuth = async (voipClient, token) => {
try {
const config = createTokenConfig(token, {
debug: true,
});
await voipClient.loginWithToken(config);
} catch (error) {
switch (error.code) {
case 'INVALID_TOKEN':
console.error('Token format is invalid');
// Request new token from your server
break;
case 'TOKEN_EXPIRED':
console.error('Token has expired');
// Refresh token and retry
break;
case 'TOKEN_NOT_FOUND':
console.error('Token not provided');
// Redirect to login
break;
}
}
};
Connection Errors
Error: CONNECTION_FAILED or NETWORK_ERROR
Symptoms: Cannot establish WebRTC connection.
Solutions:
import NetInfo from '@react-native-community/netinfo';
const handleConnectionError = async (voipClient) => {
// Check network connectivity
const netInfo = await NetInfo.fetch();
if (!netInfo.isConnected) {
console.error('No network connection');
Alert.alert('Network Error', 'Please check your internet connection');
return;
}
// Implement retry logic
const retryConnection = async (attempts = 3) => {
for (let i = 0; i < attempts; i++) {
try {
await voipClient.loginFromStoredConfig();
console.log('Reconnection successful');
return;
} catch (error) {
console.warn(`Retry attempt ${i + 1} failed:`, error.message);
if (i === attempts - 1) {
console.error('All retry attempts failed');
// Handle final failure
} else {
// Wait before retry
await new Promise(resolve => setTimeout(resolve, 2000 * (i + 1)));
}
}
}
};
await retryConnection();
};
Call Errors
Call Creation Failures
Error: CALL_FAILED or INVALID_DESTINATION
Symptoms: Cannot initiate outgoing calls.
Solutions:
const makeCallWithErrorHandling = async (voipClient, destination) => {
try {
// Validate destination format
if (!destination || destination.trim().length === 0) {
throw new Error('INVALID_DESTINATION');
}
// Check connection state
if (voipClient.currentConnectionState !== 'CONNECTED') {
throw new Error('NOT_CONNECTED');
}
const call = await voipClient.newCall(destination);
console.log('Call initiated successfully:', call.callId);
return call;
} catch (error) {
switch (error.message) {
case 'INVALID_DESTINATION':
Alert.alert('Invalid Number', 'Please enter a valid phone number');
break;
case 'NOT_CONNECTED':
Alert.alert('Connection Error', 'Please check your connection and try again');
break;
case 'CALL_LIMIT_EXCEEDED':
Alert.alert('Call Limit', 'Maximum number of concurrent calls reached');
break;
default:
console.error('Call failed:', error);
Alert.alert('Call Failed', 'Unable to place call. Please try again.');
}
}
};
Call Control Errors
Error: CALL_NOT_FOUND or INVALID_STATE
Symptoms: Call control operations fail.
Solutions:
const safeCallOperation = async (call, operation, operationName) => {
try {
if (!call) {
throw new Error('CALL_NOT_FOUND');
}
// Check call state before operation
const validStates = {
answer: ['ringing'],
hold: ['active'],
unhold: ['held'],
hangup: ['ringing', 'active', 'held'],
};
if (validStates[operation] && !validStates[operation].includes(call.state)) {
throw new Error('INVALID_STATE');
}
await call[operation]();
console.log(`${operationName} successful`);
} catch (error) {
switch (error.message) {
case 'CALL_NOT_FOUND':
console.error('Call no longer exists');
break;
case 'INVALID_STATE':
console.error(`Cannot ${operationName} call in state: ${call.state}`);
break;
default:
console.error(`${operationName} failed:`, error);
}
}
};
// Usage examples
await safeCallOperation(call, 'answer', 'Answer call');
await safeCallOperation(call, 'hold', 'Hold call');
await safeCallOperation(call, 'hangup', 'End call');
Audio Permission Errors
Error: MICROPHONE_PERMISSION_DENIED
Symptoms: No audio in calls, microphone access denied.
Solutions:
import { PermissionsAndroid, Platform } from 'react-native';
const requestAudioPermissions = async () => {
try {
if (Platform.OS === 'android') {
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.RECORD_AUDIO,
{
title: 'Microphone Permission',
message: 'This app needs microphone access for voice calls',
buttonNeutral: 'Ask Me Later',
buttonNegative: 'Cancel',
buttonPositive: 'OK',
}
);
if (granted !== PermissionsAndroid.RESULTS.GRANTED) {
throw new Error('MICROPHONE_PERMISSION_DENIED');
}
}
return true;
} catch (error) {
console.error('Audio permission error:', error);
Alert.alert(
'Microphone Permission Required',
'Please grant microphone permission in device settings to make calls',
[
{ text: 'Cancel', style: 'cancel' },
{ text: 'Settings', onPress: () => Linking.openSettings() },
]
);
return false;
}
};
Audio Routing Issues
Error: AUDIO_ROUTING_FAILED
Symptoms: Audio plays through wrong device (speaker/earpiece).
Solutions:
// Audio routing is handled automatically by the SDK
// For custom audio routing, you can listen to call state changes
const handleAudioRouting = (call) => {
call.callState$.subscribe((state) => {
switch (state) {
case 'active':
console.log('Call active - audio should route to earpiece by default');
break;
case 'held':
console.log('Call on hold - audio routing paused');
break;
}
});
};
Push Notification Errors
Token Registration Errors
Error: PUSH_TOKEN_INVALID or PUSH_REGISTRATION_FAILED
Symptoms: Push notifications not working.
Solutions:
import messaging from '@react-native-firebase/messaging';
const handlePushTokenError = async () => {
try {
// Clear and regenerate FCM token
await messaging().deleteToken();
const newToken = await messaging().getToken();
if (!newToken) {
throw new Error('PUSH_TOKEN_GENERATION_FAILED');
}
console.log('New push token:', newToken);
return newToken;
} catch (error) {
console.error('Push token error:', error);
// Fallback: Continue without push notifications
Alert.alert(
'Push Notifications',
'Unable to setup push notifications. You may miss calls when the app is closed.',
[{ text: 'OK' }]
);
}
};
Background Processing Errors
Error: BACKGROUND_PROCESSING_FAILED
Symptoms: Incoming calls not handled when app is backgrounded.
Solutions:
// Ensure proper background handler setup
messaging().setBackgroundMessageHandler(async (remoteMessage) => {
try {
console.log('Background message received:', remoteMessage);
await TelnyxVoiceApp.handleBackgroundPush(remoteMessage.data);
} catch (error) {
console.error('Background processing failed:', error);
// Log error for debugging
crashlytics().recordError(error);
}
});
Network and Connectivity Errors
WebRTC Connection Issues
Error: WEBRTC_CONNECTION_FAILED or ICE_CONNECTION_FAILED
Symptoms: Calls connect but no audio, or connection drops frequently.
Solutions:
const diagnoseNetworkIssues = async () => {
const netInfo = await NetInfo.fetch();
console.log('Network diagnostics:', {
isConnected: netInfo.isConnected,
type: netInfo.type,
isInternetReachable: netInfo.isInternetReachable,
details: netInfo.details,
});
// Check for specific network issues
if (netInfo.type === 'cellular' && netInfo.details?.cellularGeneration === '2g') {
Alert.alert(
'Network Warning',
'Your connection may be too slow for voice calls. Try connecting to Wi-Fi.'
);
}
if (!netInfo.isInternetReachable) {
Alert.alert(
'Connection Issue',
'Unable to reach the internet. Please check your connection.'
);
}
};
Firewall and NAT Issues
Error: NAT_TRAVERSAL_FAILED or FIREWALL_BLOCKED
Symptoms: Cannot connect to WebRTC servers, especially on corporate networks.
Solutions:
const checkNetworkRestrictions = () => {
console.log('If experiencing connection issues on corporate networks:');
console.log('- Ensure UDP traffic is allowed');
console.log('- Check if STUN/TURN servers are accessible');
console.log('- Verify WebSocket connections are permitted');
Alert.alert(
'Network Configuration',
'If you\'re on a corporate network, please contact your IT administrator to ensure VoIP traffic is allowed.',
[{ text: 'OK' }]
);
};
Memory Leaks
Error: MEMORY_WARNING or app crashes
Symptoms: App becomes slow or crashes after extended use.
Solutions:
// Proper cleanup of subscriptions
const useCallSubscription = (call) => {
useEffect(() => {
if (!call) return;
const subscription = call.callState$.subscribe((state) => {
console.log('Call state:', state);
});
// Critical: Always unsubscribe
return () => {
subscription.unsubscribe();
};
}, [call]);
};
// Cleanup client resources
const cleanupVoipClient = (voipClient) => {
useEffect(() => {
return () => {
// Cleanup when component unmounts
voipClient.logout().catch(console.error);
};
}, [voipClient]);
};
Error: Slow UI, delayed call operations
Solutions:
// Optimize state updates
const useOptimizedCallState = (voipClient) => {
const [calls, setCalls] = useState([]);
useEffect(() => {
// Throttle rapid state updates
const subscription = voipClient.calls$
.pipe(
throttleTime(100), // Limit updates to once per 100ms
distinctUntilChanged() // Only update when actually changed
)
.subscribe(setCalls);
return () => subscription.unsubscribe();
}, [voipClient]);
return calls;
};
Enable Debug Logging
import { createTelnyxVoipClient } from '@telnyx/react-voice-commons-sdk';
// Enable comprehensive debug logging
const voipClient = createTelnyxVoipClient({
debug: true, // Enable detailed logging
});
// Custom error logging
const logError = (context, error) => {
console.error(`[${context}] Error:`, {
message: error.message,
code: error.code,
stack: error.stack,
timestamp: new Date().toISOString(),
});
};
Network Request Monitoring
// Monitor all network requests
const originalFetch = global.fetch;
global.fetch = (...args) => {
console.log('Network request:', args[0]);
return originalFetch(...args)
.then(response => {
console.log('Network response:', response.status, response.statusText);
return response;
})
.catch(error => {
console.error('Network error:', error);
throw error;
});
};
Call State Debugging
const debugCallState = (call) => {
call.callState$.subscribe((state) => {
console.log('Call State Debug:', {
callId: call.callId,
state: state,
destination: call.destination,
isIncoming: call.isIncoming,
duration: call.duration,
timestamp: new Date().toISOString(),
});
});
};
Error Recovery Strategies
Automatic Recovery
const createResilientVoipClient = () => {
const voipClient = createTelnyxVoipClient({
debug: __DEV__,
});
// Auto-recovery for connection issues
voipClient.connectionState$.subscribe((state) => {
if (state === 'DISCONNECTED') {
console.log('Connection lost, attempting recovery...');
setTimeout(async () => {
try {
await voipClient.loginFromStoredConfig();
console.log('Auto-recovery successful');
} catch (error) {
console.error('Auto-recovery failed:', error);
}
}, 5000); // Wait 5 seconds before retry
}
});
return voipClient;
};
Graceful Degradation
const handleGracefulDegradation = (error) => {
switch (error.code) {
case 'PUSH_NOTIFICATIONS_UNAVAILABLE':
// Continue without push notifications
console.warn('Push notifications disabled, app must stay foreground');
break;
case 'MICROPHONE_PERMISSION_DENIED':
// Disable calling features
console.warn('Microphone access denied, calling disabled');
break;
case 'NETWORK_UNREACHABLE':
// Show offline mode
console.warn('Network unreachable, entering offline mode');
break;
default:
// General error handling
console.error('Unhandled error, continuing with limited functionality');
}
};
Best Practices
Error Handling Patterns
- Always wrap async operations in try-catch
- Provide user-friendly error messages
- Log detailed error information for debugging
- Implement retry logic for transient failures
- Gracefully degrade functionality when possible
Monitoring and Analytics
// Error tracking with analytics
const trackError = (error, context) => {
// Send to your analytics service
analytics().logEvent('voip_error', {
error_code: error.code,
error_message: error.message,
context: context,
platform: Platform.OS,
app_version: DeviceInfo.getVersion(),
});
};
Testing Error Scenarios
// Test error handling in development
const testErrorScenarios = async (voipClient) => {
if (__DEV__) {
// Test invalid credentials
try {
await voipClient.login(createCredentialConfig('invalid', 'invalid'));
} catch (error) {
console.log('✓ Invalid credentials handled correctly');
}
// Test network disconnection
// (manually disconnect network to test)
// Test invalid phone numbers
try {
await voipClient.newCall('invalid_number');
} catch (error) {
console.log('✓ Invalid destination handled correctly');
}
}
};
Getting Help
When encountering persistent issues:
- Enable debug logging and collect detailed logs
- Document reproduction steps clearly
- Include device and OS information
- Check the error handling guides for your specific issue
- Contact Telnyx Support with comprehensive information
See Also