0
# Exception Handling
1
2
Comprehensive exception hierarchy for handling Socket.IO-specific errors including connection failures, timeouts, namespace issues, and disconnection scenarios. These exceptions provide detailed error information for robust error handling in Socket.IO applications.
3
4
## Capabilities
5
6
### SocketIOError
7
8
Base exception class for all Socket.IO-related errors. All other Socket.IO exceptions inherit from this class.
9
10
```python { .api }
11
class SocketIOError(Exception):
12
"""
13
Base exception class for all Socket.IO errors.
14
15
Inherits from: Exception
16
17
This is the base class for all Socket.IO-specific exceptions.
18
Catch this exception to handle any Socket.IO-related error.
19
"""
20
```
21
22
#### Usage Example
23
24
```python
25
import socketio
26
27
sio = socketio.Client()
28
29
try:
30
sio.connect('http://localhost:5000')
31
sio.emit('message', {'text': 'Hello'})
32
except socketio.SocketIOError as e:
33
print(f'Socket.IO error occurred: {e}')
34
# Handle any Socket.IO-related error
35
```
36
37
### ConnectionError
38
39
Base class for connection-related errors. Raised when there are issues establishing or maintaining connections.
40
41
```python { .api }
42
class ConnectionError(SocketIOError):
43
"""
44
Base class for connection-related errors.
45
46
Inherits from: SocketIOError
47
48
This exception is raised when there are problems with Socket.IO connections,
49
such as network issues, server unavailability, or connection failures.
50
"""
51
```
52
53
#### Usage Example
54
55
```python
56
import socketio
57
58
sio = socketio.Client()
59
60
try:
61
sio.connect('http://unreachable-server:5000')
62
except socketio.ConnectionError as e:
63
print(f'Connection error: {e}')
64
# Handle connection-related issues
65
# Try alternative server, show offline mode, etc.
66
```
67
68
### ConnectionRefusedError
69
70
Raised when a connection attempt is refused by the server, typically due to authentication failures or server policies.
71
72
```python { .api }
73
class ConnectionRefusedError(ConnectionError):
74
"""
75
Connection refused exception.
76
77
Inherits from: ConnectionError
78
79
Attributes:
80
error_args (dict): Dictionary containing error details with 'message' key
81
and optional 'data' key for additional information
82
"""
83
84
def __init__(self, *args):
85
"""
86
Initialize the connection refused error.
87
88
Args:
89
*args: Error arguments, typically a message string or error dict
90
"""
91
```
92
93
#### Usage Example
94
95
```python
96
import socketio
97
98
sio = socketio.Client()
99
100
@sio.event
101
def connect_error(data):
102
print(f'Connection failed: {data}')
103
104
try:
105
sio.connect('http://localhost:5000', auth={'token': 'invalid_token'})
106
except socketio.ConnectionRefusedError as e:
107
print(f'Connection refused: {e}')
108
if hasattr(e, 'error_args'):
109
error_info = e.error_args
110
print(f'Error message: {error_info.get("message")}')
111
if 'data' in error_info:
112
print(f'Additional data: {error_info["data"]}')
113
114
# Handle authentication failure
115
# Prompt for new credentials, redirect to login, etc.
116
117
# Server-side example that raises ConnectionRefusedError
118
sio_server = socketio.Server()
119
120
@sio_server.event
121
def connect(sid, environ, auth):
122
if not auth or auth.get('token') != 'valid_token':
123
raise socketio.ConnectionRefusedError('Authentication failed')
124
print(f'Client {sid} authenticated successfully')
125
```
126
127
### TimeoutError
128
129
Raised when a Socket.IO operation exceeds its specified timeout period.
130
131
```python { .api }
132
class TimeoutError(SocketIOError):
133
"""
134
Timeout-related exception.
135
136
Inherits from: SocketIOError
137
138
This exception is raised when Socket.IO operations take longer than
139
the specified timeout period. Common scenarios include call() operations
140
waiting for responses and connection attempts timing out.
141
"""
142
```
143
144
#### Usage Example
145
146
```python
147
import socketio
148
149
sio = socketio.Client()
150
sio.connect('http://localhost:5000')
151
152
try:
153
# This will raise TimeoutError if server doesn't respond within 5 seconds
154
response = sio.call('slow_operation', {'data': 'test'}, timeout=5)
155
print(f'Response: {response}')
156
except socketio.TimeoutError as e:
157
print(f'Operation timed out: {e}')
158
# Handle timeout scenario
159
# Show loading indicator, retry, or provide fallback
160
161
# Async client example
162
async def async_example():
163
sio = socketio.AsyncClient()
164
await sio.connect('http://localhost:5000')
165
166
try:
167
response = await sio.call('async_operation', timeout=3)
168
print(f'Async response: {response}')
169
except socketio.TimeoutError as e:
170
print(f'Async operation timed out: {e}')
171
finally:
172
await sio.disconnect()
173
174
# Server-side handler that might cause timeout
175
@sio_server.event
176
def slow_operation(sid, data):
177
import time
178
time.sleep(10) # This will cause TimeoutError on client
179
return {'result': 'completed'}
180
```
181
182
### BadNamespaceError
183
184
Raised when attempting to use an invalid or unauthorized namespace.
185
186
```python { .api }
187
class BadNamespaceError(SocketIOError):
188
"""
189
Invalid namespace exception.
190
191
Inherits from: SocketIOError
192
193
This exception is raised when:
194
- Attempting to connect to a namespace that doesn't exist
195
- Using a namespace that the client is not authorized to access
196
- Malformed namespace names
197
"""
198
```
199
200
#### Usage Example
201
202
```python
203
import socketio
204
205
sio = socketio.Client()
206
207
try:
208
sio.connect('http://localhost:5000', namespaces=['/chat', '/invalid-namespace'])
209
except socketio.BadNamespaceError as e:
210
print(f'Invalid namespace: {e}')
211
# Handle namespace error
212
# Connect to default namespace or show error message
213
214
# Using specific namespace that might not exist
215
try:
216
sio.emit('message', {'text': 'Hello'}, namespace='/nonexistent')
217
except socketio.BadNamespaceError as e:
218
print(f'Namespace error: {e}')
219
# Fall back to default namespace
220
sio.emit('message', {'text': 'Hello'})
221
222
# Server-side namespace configuration
223
sio_server = socketio.Server()
224
225
# Only allow specific namespaces
226
@sio_server.event
227
def connect(sid, environ, auth):
228
# Validate namespace access based on authentication
229
namespace = environ.get('PATH_INFO', '/').split('/')[1]
230
if namespace not in ['chat', 'game'] and auth.get('role') != 'admin':
231
raise socketio.BadNamespaceError(f'Access denied to namespace: /{namespace}')
232
```
233
234
### DisconnectedError
235
236
Raised when attempting to perform operations on a disconnected client or when unexpected disconnections occur.
237
238
```python { .api }
239
class DisconnectedError(SocketIOError):
240
"""
241
Client disconnection exception.
242
243
Inherits from: SocketIOError
244
245
This exception is raised when:
246
- Attempting to emit events on a disconnected client
247
- Trying to access session data for disconnected clients
248
- Performing operations that require an active connection
249
"""
250
```
251
252
#### Usage Example
253
254
```python
255
import socketio
256
257
sio = socketio.Client()
258
259
@sio.event
260
def disconnect():
261
print('Disconnected from server')
262
263
try:
264
sio.connect('http://localhost:5000')
265
266
# Simulate network interruption or server shutdown
267
# ... connection is lost ...
268
269
# This will raise DisconnectedError
270
sio.emit('message', {'text': 'Hello'})
271
272
except socketio.DisconnectedError as e:
273
print(f'Client disconnected: {e}')
274
# Handle disconnection
275
# Attempt reconnection, switch to offline mode, etc.
276
277
try:
278
print('Attempting to reconnect...')
279
sio.connect('http://localhost:5000')
280
sio.emit('message', {'text': 'Reconnected'})
281
except socketio.ConnectionError as reconnect_error:
282
print(f'Reconnection failed: {reconnect_error}')
283
284
# Server-side example
285
sio_server = socketio.Server()
286
287
@sio_server.event
288
def handle_message(sid, data):
289
try:
290
# Try to access session data
291
session = sio_server.get_session(sid)
292
# Process message with session data
293
sio_server.emit('response', {'processed': data}, room=sid)
294
except socketio.DisconnectedError as e:
295
print(f'Client {sid} disconnected during processing: {e}')
296
# Clean up any resources associated with this client
297
298
# Async server example
299
@async_sio_server.event
300
async def async_handle_message(sid, data):
301
try:
302
async with async_sio_server.session(sid) as session:
303
session['last_message'] = data
304
await async_sio_server.emit('response', {'received': data}, room=sid)
305
except socketio.DisconnectedError as e:
306
print(f'Client {sid} disconnected: {e}')
307
```
308
309
## Exception Handling Patterns
310
311
### Comprehensive Error Handling
312
313
```python
314
import socketio
315
import logging
316
317
logger = logging.getLogger(__name__)
318
319
sio = socketio.Client(logger=True)
320
321
def safe_emit(event, data, **kwargs):
322
"""Safely emit events with comprehensive error handling."""
323
try:
324
return sio.emit(event, data, **kwargs)
325
except socketio.DisconnectedError:
326
logger.error('Cannot emit: client disconnected')
327
# Attempt reconnection
328
try_reconnect()
329
except socketio.BadNamespaceError as e:
330
logger.error(f'Invalid namespace: {e}')
331
# Fall back to default namespace
332
return sio.emit(event, data)
333
except socketio.SocketIOError as e:
334
logger.error(f'Socket.IO error: {e}')
335
# Handle generic Socket.IO errors
336
except Exception as e:
337
logger.error(f'Unexpected error: {e}')
338
339
def safe_call(event, data, timeout=30):
340
"""Safely call with response handling."""
341
try:
342
return sio.call(event, data, timeout=timeout)
343
except socketio.TimeoutError:
344
logger.warning(f'Call to {event} timed out after {timeout}s')
345
return None
346
except socketio.DisconnectedError:
347
logger.error('Cannot call: client disconnected')
348
if try_reconnect():
349
# Retry after reconnection
350
return sio.call(event, data, timeout=timeout)
351
return None
352
except socketio.SocketIOError as e:
353
logger.error(f'Call failed: {e}')
354
return None
355
356
def try_reconnect(max_attempts=3):
357
"""Attempt to reconnect with exponential backoff."""
358
import time
359
360
for attempt in range(max_attempts):
361
try:
362
delay = 2 ** attempt # Exponential backoff
363
logger.info(f'Reconnection attempt {attempt + 1} in {delay}s')
364
time.sleep(delay)
365
366
sio.connect('http://localhost:5000')
367
logger.info('Reconnected successfully')
368
return True
369
370
except socketio.ConnectionRefusedError as e:
371
logger.error(f'Connection refused: {e}')
372
# Don't retry on authentication failures
373
break
374
except socketio.ConnectionError as e:
375
logger.warning(f'Reconnection attempt {attempt + 1} failed: {e}')
376
377
logger.error('All reconnection attempts failed')
378
return False
379
```
380
381
### Server-Side Error Handling
382
383
```python
384
import socketio
385
386
sio = socketio.Server()
387
388
@sio.event
389
def connect(sid, environ, auth):
390
try:
391
# Validate authentication
392
if not validate_auth(auth):
393
raise socketio.ConnectionRefusedError('Invalid credentials')
394
395
# Initialize client session
396
sio.save_session(sid, {
397
'user_id': auth['user_id'],
398
'connected_at': time.time()
399
})
400
401
sio.enter_room(sid, 'authenticated_users')
402
sio.emit('welcome', {'message': 'Connected successfully'}, room=sid)
403
404
except socketio.ConnectionRefusedError:
405
# Re-raise authentication errors
406
raise
407
except Exception as e:
408
logger.error(f'Connection error for {sid}: {e}')
409
raise socketio.ConnectionRefusedError('Internal server error')
410
411
@sio.event
412
def handle_message(sid, data):
413
try:
414
# Validate client connection
415
session = sio.get_session(sid)
416
417
# Process message
418
result = process_message(data, session)
419
sio.emit('message_result', result, room=sid)
420
421
except socketio.DisconnectedError:
422
logger.warning(f'Client {sid} disconnected during message processing')
423
except Exception as e:
424
logger.error(f'Message processing error for {sid}: {e}')
425
sio.emit('error', {'message': 'Message processing failed'}, room=sid)
426
427
def validate_auth(auth):
428
"""Validate authentication credentials."""
429
if not auth or 'token' not in auth:
430
return False
431
# Implement your authentication logic
432
return auth['token'] == 'valid_token'
433
434
def process_message(data, session):
435
"""Process incoming message with error handling."""
436
if not data or 'content' not in data:
437
raise ValueError('Invalid message format')
438
439
# Process the message
440
return {
441
'status': 'processed',
442
'user_id': session['user_id'],
443
'processed_at': time.time()
444
}
445
```
446
447
### Context Manager for Connection Handling
448
449
```python
450
import socketio
451
from contextlib import contextmanager
452
453
@contextmanager
454
def socket_connection(url, **kwargs):
455
"""Context manager for safe Socket.IO connections."""
456
sio = socketio.Client()
457
try:
458
sio.connect(url, **kwargs)
459
yield sio
460
except socketio.ConnectionError as e:
461
print(f'Failed to connect: {e}')
462
raise
463
finally:
464
if sio.connected:
465
sio.disconnect()
466
467
# Usage
468
try:
469
with socket_connection('http://localhost:5000') as sio:
470
sio.emit('message', {'text': 'Hello'})
471
response = sio.call('get_data', timeout=5)
472
print(f'Response: {response}')
473
except socketio.TimeoutError:
474
print('Operation timed out')
475
except socketio.SocketIOError as e:
476
print(f'Socket.IO error: {e}')
477
```