0
# Error Handling
1
2
obsws-python provides comprehensive error handling with specific exception types for different failure scenarios. Understanding these errors is crucial for building robust OBS automation applications.
3
4
## Exception Hierarchy
5
6
### Base Exception
7
8
```python { .api }
9
class OBSSDKError(Exception):
10
"""Base class for all OBSSDK errors."""
11
```
12
13
### Specific Exception Types
14
15
```python { .api }
16
class OBSSDKTimeoutError(OBSSDKError):
17
"""
18
Exception raised when a connection times out.
19
20
Raised when:
21
- Connection to OBS WebSocket times out
22
- Request sends but response times out
23
- Event receiving times out
24
"""
25
26
class OBSSDKRequestError(OBSSDKError):
27
"""
28
Exception raised when a request returns an error code.
29
30
Attributes:
31
- req_name (str): Name of the failed request
32
- code (int): OBS WebSocket error code
33
"""
34
35
def __init__(self, req_name, code, comment):
36
self.req_name = req_name
37
self.code = code
38
# message automatically formatted as: "Request {req_name} returned code {code}. With message: {comment}"
39
```
40
41
## Common Error Scenarios
42
43
### Connection Errors
44
45
```python
46
import obsws_python as obs
47
from obsws_python.error import OBSSDKError, OBSSDKTimeoutError
48
49
try:
50
# Wrong host/port
51
client = obs.ReqClient(host='nonexistent', port=9999, timeout=5)
52
except (ConnectionRefusedError, TimeoutError) as e:
53
print(f"Connection failed: {e}")
54
except OBSSDKError as e:
55
print(f"OBS SDK error: {e}")
56
57
try:
58
# Wrong password
59
client = obs.ReqClient(password='wrongpassword')
60
except OBSSDKError as e:
61
print(f"Authentication failed: {e}")
62
63
try:
64
# Connection timeout
65
client = obs.ReqClient(host='slow-server.com', timeout=1)
66
except OBSSDKTimeoutError as e:
67
print(f"Connection timed out: {e}")
68
```
69
70
### Request Errors
71
72
```python
73
import obsws_python as obs
74
from obsws_python.error import OBSSDKRequestError
75
76
client = obs.ReqClient()
77
78
try:
79
# Non-existent scene
80
client.set_current_program_scene("NonExistentScene")
81
except OBSSDKRequestError as e:
82
print(f"Request failed: {e.req_name}")
83
print(f"Error code: {e.code}")
84
print(f"Full error: {e}")
85
86
try:
87
# Invalid input name
88
client.toggle_input_mute("NonExistentInput")
89
except OBSSDKRequestError as e:
90
if e.code == 600: # ResourceNotFound
91
print(f"Input not found: {e.req_name}")
92
else:
93
print(f"Unexpected error {e.code}: {e}")
94
```
95
96
### Event Client Errors
97
98
```python
99
import obsws_python as obs
100
from obsws_python.error import OBSSDKTimeoutError
101
102
try:
103
client = obs.EventClient(timeout=10)
104
105
# Event client runs in background thread
106
# Errors typically occur during connection or event processing
107
108
except OBSSDKTimeoutError as e:
109
print(f"Event client timed out: {e}")
110
except Exception as e:
111
print(f"Event client error: {e}")
112
```
113
114
## Error Codes
115
116
OBS WebSocket returns specific error codes for different failure scenarios:
117
118
### Common Error Codes
119
120
| Code | Name | Description |
121
|------|------|-------------|
122
| 100 | Success | Request completed successfully |
123
| 200 | MissingRequestType | Request type not specified |
124
| 201 | UnknownRequestType | Unknown request type |
125
| 202 | GenericError | Generic error occurred |
126
| 203 | UnsupportedRequestBatchExecutionType | Unsupported batch execution type |
127
| 300 | MissingRequestField | Required request field missing |
128
| 301 | MissingRequestData | Request data missing |
129
| 400 | InvalidRequestField | Invalid request field value |
130
| 401 | InvalidRequestFieldType | Invalid request field type |
131
| 402 | RequestFieldOutOfRange | Request field value out of range |
132
| 403 | RequestFieldEmpty | Request field is empty |
133
| 500 | OutputRunning | Output is running |
134
| 501 | OutputNotRunning | Output is not running |
135
| 502 | OutputPaused | Output is paused |
136
| 503 | OutputNotPaused | Output is not paused |
137
| 504 | OutputDisabled | Output is disabled |
138
| 505 | StudioModeActive | Studio mode is active |
139
| 506 | StudioModeNotActive | Studio mode is not active |
140
| 600 | ResourceNotFound | Resource not found |
141
| 601 | ResourceAlreadyExists | Resource already exists |
142
| 602 | InvalidResourceType | Invalid resource type |
143
| 603 | NotEnoughResources | Not enough resources |
144
| 604 | InvalidResourceState | Invalid resource state |
145
| 605 | InvalidInputKind | Invalid input kind |
146
| 606 | ResourceNotConfigurable | Resource not configurable |
147
| 607 | InvalidFilterKind | Invalid filter kind |
148
149
## Error Handling Patterns
150
151
### Basic Error Handling
152
153
```python
154
import obsws_python as obs
155
from obsws_python.error import OBSSDKError, OBSSDKRequestError, OBSSDKTimeoutError
156
157
def safe_obs_operation(client, operation_name, operation_func):
158
"""
159
Safely execute an OBS operation with error handling.
160
161
Parameters:
162
- client: OBS client instance
163
- operation_name: Description of operation for logging
164
- operation_func: Function to execute
165
166
Returns:
167
- (success: bool, result: any, error: str)
168
"""
169
try:
170
result = operation_func()
171
print(f"β {operation_name} succeeded")
172
return True, result, None
173
174
except OBSSDKRequestError as e:
175
error_msg = f"{operation_name} failed: {e.req_name} returned code {e.code}"
176
print(f"β {error_msg}")
177
return False, None, error_msg
178
179
except OBSSDKTimeoutError as e:
180
error_msg = f"{operation_name} timed out: {e}"
181
print(f"β±οΈ {error_msg}")
182
return False, None, error_msg
183
184
except OBSSDKError as e:
185
error_msg = f"{operation_name} failed: {e}"
186
print(f"π₯ {error_msg}")
187
return False, None, error_msg
188
189
# Usage
190
client = obs.ReqClient()
191
192
success, result, error = safe_obs_operation(
193
client,
194
"Scene switch",
195
lambda: client.set_current_program_scene("Scene 2")
196
)
197
198
if success:
199
print("Scene switched successfully")
200
else:
201
print(f"Scene switch failed: {error}")
202
```
203
204
### Retry Logic
205
206
```python
207
import obsws_python as obs
208
from obsws_python.error import OBSSDKTimeoutError, OBSSDKRequestError
209
import time
210
211
def retry_operation(operation_func, max_retries=3, delay=1.0):
212
"""
213
Retry an OBS operation with exponential backoff.
214
215
Parameters:
216
- operation_func: Function to retry
217
- max_retries: Maximum number of retry attempts
218
- delay: Initial delay between retries (doubles each attempt)
219
220
Returns:
221
- Result of successful operation or raises last exception
222
"""
223
last_exception = None
224
225
for attempt in range(max_retries + 1):
226
try:
227
return operation_func()
228
229
except OBSSDKTimeoutError as e:
230
last_exception = e
231
if attempt < max_retries:
232
wait_time = delay * (2 ** attempt)
233
print(f"Timeout on attempt {attempt + 1}, retrying in {wait_time}s...")
234
time.sleep(wait_time)
235
else:
236
print(f"Operation failed after {max_retries + 1} attempts")
237
238
except OBSSDKRequestError as e:
239
# Don't retry request errors (they won't succeed)
240
print(f"Request error (not retrying): {e}")
241
raise
242
243
except OBSSDKError as e:
244
last_exception = e
245
if attempt < max_retries:
246
print(f"Error on attempt {attempt + 1}, retrying...")
247
time.sleep(delay)
248
else:
249
print(f"Operation failed after {max_retries + 1} attempts")
250
251
raise last_exception
252
253
# Usage
254
client = obs.ReqClient()
255
256
try:
257
result = retry_operation(
258
lambda: client.get_version(),
259
max_retries=3,
260
delay=1.0
261
)
262
print(f"Got version: {result.obs_version}")
263
264
except Exception as e:
265
print(f"Failed to get version after retries: {e}")
266
```
267
268
### Context Manager with Error Handling
269
270
```python
271
import obsws_python as obs
272
from obsws_python.error import OBSSDKError
273
from contextlib import contextmanager
274
275
@contextmanager
276
def obs_client_safe(**kwargs):
277
"""
278
Context manager for safe OBS client creation and cleanup.
279
"""
280
client = None
281
try:
282
client = obs.ReqClient(**kwargs)
283
print("β Connected to OBS")
284
yield client
285
286
except OBSSDKError as e:
287
print(f"β Failed to connect to OBS: {e}")
288
raise
289
290
finally:
291
if client:
292
try:
293
client.disconnect()
294
print("π Disconnected from OBS")
295
except Exception as e:
296
print(f"β οΈ Error during disconnect: {e}")
297
298
# Usage
299
try:
300
with obs_client_safe(timeout=10) as client:
301
# Do operations with error handling
302
try:
303
version = client.get_version()
304
print(f"OBS Version: {version.obs_version}")
305
306
client.set_current_program_scene("Scene 1")
307
print("Scene changed successfully")
308
309
except OBSSDKRequestError as e:
310
print(f"Operation failed: {e}")
311
# Continue with other operations...
312
313
except OBSSDKError:
314
print("Could not establish OBS connection")
315
```
316
317
### Event Client Error Handling
318
319
```python
320
import obsws_python as obs
321
from obsws_python.error import OBSSDKError, OBSSDKTimeoutError
322
import threading
323
import time
324
325
class RobustEventClient:
326
def __init__(self, **kwargs):
327
self.client = None
328
self.connection_params = kwargs
329
self.running = False
330
self.reconnect_attempts = 0
331
self.max_reconnects = 5
332
333
def connect(self):
334
"""Connect with error handling and retry logic."""
335
while self.reconnect_attempts < self.max_reconnects:
336
try:
337
if self.client:
338
self.client.disconnect()
339
340
self.client = obs.EventClient(**self.connection_params)
341
self.reconnect_attempts = 0
342
print("β Event client connected")
343
return True
344
345
except OBSSDKTimeoutError as e:
346
self.reconnect_attempts += 1
347
wait_time = min(30, 2 ** self.reconnect_attempts)
348
print(f"β±οΈ Connection timeout (attempt {self.reconnect_attempts}), retrying in {wait_time}s...")
349
time.sleep(wait_time)
350
351
except OBSSDKError as e:
352
print(f"β Connection failed: {e}")
353
return False
354
355
print(f"π₯ Failed to connect after {self.max_reconnects} attempts")
356
return False
357
358
def register_callbacks(self, callbacks):
359
"""Register event callbacks with error handling."""
360
if not self.client:
361
print("β No client connected")
362
return False
363
364
try:
365
self.client.callback.register(callbacks)
366
return True
367
except Exception as e:
368
print(f"β Failed to register callbacks: {e}")
369
return False
370
371
def start_monitoring(self):
372
"""Start monitoring with automatic reconnection."""
373
self.running = True
374
375
def monitor_loop():
376
while self.running:
377
if not self.client or not self.connect():
378
time.sleep(5)
379
continue
380
381
try:
382
# Keep connection alive
383
while self.running:
384
time.sleep(1)
385
386
except Exception as e:
387
print(f"β οΈ Event monitoring error: {e}")
388
self.reconnect_attempts += 1
389
time.sleep(2)
390
391
self.monitor_thread = threading.Thread(target=monitor_loop, daemon=True)
392
self.monitor_thread.start()
393
394
def stop_monitoring(self):
395
"""Stop monitoring and disconnect."""
396
self.running = False
397
if self.client:
398
try:
399
self.client.disconnect()
400
except Exception as e:
401
print(f"β οΈ Error during disconnect: {e}")
402
403
# Usage
404
def on_scene_changed(data):
405
print(f"Scene changed: {data.scene_name}")
406
407
def on_connection_error(error):
408
print(f"Connection error: {error}")
409
410
# Create robust event client
411
event_client = RobustEventClient(
412
host='localhost',
413
port=4455,
414
password='mypassword',
415
timeout=10
416
)
417
418
if event_client.connect():
419
event_client.register_callbacks([on_scene_changed])
420
event_client.start_monitoring()
421
422
try:
423
input("Event monitoring active. Press Enter to stop...\n")
424
finally:
425
event_client.stop_monitoring()
426
else:
427
print("Failed to establish initial connection")
428
```
429
430
## Debugging Tips
431
432
### Enable Logging
433
434
```python
435
import logging
436
import obsws_python as obs
437
438
# Enable debug logging to see raw WebSocket messages
439
logging.basicConfig(level=logging.DEBUG)
440
441
client = obs.ReqClient()
442
# Now you'll see detailed logs of all WebSocket communication
443
```
444
445
### Error Analysis Helper
446
447
```python
448
import obsws_python as obs
449
from obsws_python.error import OBSSDKRequestError
450
451
def analyze_request_error(error):
452
"""Analyze OBS request error and provide helpful information."""
453
if not isinstance(error, OBSSDKRequestError):
454
return f"Not an OBSSDKRequestError: {type(error).__name__}"
455
456
analysis = f"Request: {error.req_name}\nError Code: {error.code}\n"
457
458
# Common error code explanations
459
explanations = {
460
600: "Resource not found - check names are correct and resources exist",
461
601: "Resource already exists - trying to create something that already exists",
462
500: "Output already running - trying to start already active output",
463
501: "Output not running - trying to stop inactive output",
464
505: "Studio mode is active - operation requires studio mode to be disabled",
465
506: "Studio mode not active - operation requires studio mode to be enabled",
466
402: "Value out of range - check parameter bounds",
467
403: "Field is empty - required parameter is missing or empty"
468
}
469
470
if error.code in explanations:
471
analysis += f"Likely cause: {explanations[error.code]}"
472
else:
473
analysis += "Check OBS WebSocket documentation for error code details"
474
475
return analysis
476
477
# Usage
478
client = obs.ReqClient()
479
480
try:
481
client.set_current_program_scene("NonExistentScene")
482
except OBSSDKRequestError as e:
483
print(analyze_request_error(e))
484
```