0
# Exception Handling
1
2
pybind11 provides seamless translation between C++ exceptions and Python exceptions, allowing natural error handling across the language boundary. It supports both automatic translation of standard exceptions and registration of custom exception types.
3
4
## Capabilities
5
6
### Automatic Exception Translation
7
8
Standard C++ exceptions are automatically translated to appropriate Python exceptions.
9
10
```cpp { .api }
11
// Automatic translations:
12
// std::exception -> RuntimeError
13
// std::bad_alloc -> MemoryError
14
// std::domain_error -> ValueError
15
// std::invalid_argument -> ValueError
16
// std::length_error -> ValueError
17
// std::out_of_range -> IndexError
18
// std::range_error -> ValueError
19
// std::overflow_error -> OverflowError
20
// std::underflow_error -> ArithmeticError
21
```
22
23
### Python Exception Capture
24
25
Capture and handle Python exceptions in C++ code.
26
27
```cpp { .api }
28
class error_already_set : public std::exception {
29
public:
30
// Construct from current Python exception state
31
error_already_set();
32
33
// Query exception information
34
bool matches(handle exc_type) const;
35
const char* what() const noexcept override;
36
37
// Access exception components
38
object type() const;
39
object value() const;
40
object trace() const;
41
42
// Control exception state
43
void restore(); // Restore exception to Python
44
void discard_as_unraisable(object err_context);
45
46
// Static utilities
47
static bool matches(handle exc_type);
48
static void clear();
49
};
50
```
51
52
### Built-in Python Exception Types
53
54
Wrapper classes for standard Python exception types.
55
56
```cpp { .api }
57
class builtin_exception : public object {
58
// Base class for Python built-in exceptions
59
};
60
61
class stop_iteration : public builtin_exception {
62
// Python StopIteration exception
63
public:
64
stop_iteration();
65
stop_iteration(const char* what);
66
stop_iteration(const std::string& what);
67
};
68
69
class index_error : public builtin_exception {
70
// Python IndexError exception
71
public:
72
index_error();
73
index_error(const char* what);
74
index_error(const std::string& what);
75
};
76
77
class key_error : public builtin_exception {
78
// Python KeyError exception
79
public:
80
key_error();
81
key_error(const char* what);
82
key_error(const std::string& what);
83
};
84
85
class value_error : public builtin_exception {
86
// Python ValueError exception
87
public:
88
value_error();
89
value_error(const char* what);
90
value_error(const std::string& what);
91
};
92
93
class type_error : public builtin_exception {
94
// Python TypeError exception
95
public:
96
type_error();
97
type_error(const char* what);
98
type_error(const std::string& what);
99
};
100
101
class attribute_error : public builtin_exception {
102
// Python AttributeError exception
103
public:
104
attribute_error();
105
attribute_error(const char* what);
106
attribute_error(const std::string& what);
107
};
108
```
109
110
### Custom Exception Registration
111
112
Register custom C++ exception types for automatic translation.
113
114
```cpp { .api }
115
// Register custom exception type
116
template<typename CppException>
117
exception<CppException>& register_exception(module_ &m, const char *name,
118
handle base = PyExc_Exception);
119
120
// Exception class template for custom types
121
template<typename CppException>
122
class exception : public builtin_exception {
123
public:
124
exception(handle scope, const char *name, handle base = handle());
125
126
// Set translator function
127
void set_translator(std::function<void(const CppException&)> translator);
128
};
129
```
130
131
### Exception Translation Utilities
132
133
Utilities for handling exception translation and error states.
134
135
```cpp { .api }
136
// Register exception translator
137
template<typename CppException>
138
void register_exception_translator(std::function<void(const CppException&)> translator);
139
140
// Manually raise Python exceptions
141
[[noreturn]] void pybind11_fail(const char* reason);
142
[[noreturn]] void pybind11_fail(const std::string& reason);
143
144
// Check for Python errors
145
bool PyErr_Occurred();
146
void PyErr_Clear();
147
void PyErr_Print();
148
149
// Exception context management
150
class error_scope {
151
public:
152
error_scope();
153
~error_scope();
154
155
bool has_error() const;
156
error_already_set get_error();
157
};
158
```
159
160
### Casting Exceptions
161
162
Special exception type for type casting failures.
163
164
```cpp { .api }
165
class cast_error : public std::runtime_error {
166
// Thrown when type casting fails
167
public:
168
cast_error(const std::string& message);
169
cast_error(const char* message);
170
};
171
172
// Reference casting failure
173
class reference_cast_error : public cast_error {
174
public:
175
reference_cast_error(const std::string& message);
176
};
177
```
178
179
## Usage Examples
180
181
### Basic Exception Handling
182
183
```cpp
184
#include <pybind11/pybind11.h>
185
#include <stdexcept>
186
187
namespace py = pybind11;
188
189
int divide(int a, int b) {
190
if (b == 0) {
191
throw std::invalid_argument("Division by zero");
192
}
193
return a / b;
194
}
195
196
std::string access_vector(const std::vector<std::string>& vec, size_t index) {
197
if (index >= vec.size()) {
198
throw std::out_of_range("Index out of range");
199
}
200
return vec[index];
201
}
202
203
PYBIND11_MODULE(example, m) {
204
// These exceptions are automatically translated:
205
// std::invalid_argument -> ValueError
206
// std::out_of_range -> IndexError
207
m.def("divide", ÷);
208
m.def("access_vector", &access_vector);
209
}
210
```
211
212
### Custom Exception Types
213
214
```cpp
215
#include <pybind11/pybind11.h>
216
217
namespace py = pybind11;
218
219
// Custom C++ exception
220
class NetworkError : public std::runtime_error {
221
public:
222
NetworkError(const std::string& message, int error_code)
223
: std::runtime_error(message), error_code_(error_code) {}
224
225
int error_code() const { return error_code_; }
226
227
private:
228
int error_code_;
229
};
230
231
// Function that throws custom exception
232
void connect_to_server(const std::string& address) {
233
// Simulate network error
234
throw NetworkError("Connection failed to " + address, 404);
235
}
236
237
PYBIND11_MODULE(example, m) {
238
// Register custom exception
239
py::register_exception<NetworkError>(m, "NetworkError");
240
241
m.def("connect_to_server", &connect_to_server);
242
}
243
244
// Python usage:
245
// try:
246
// connect_to_server("example.com")
247
// except NetworkError as e:
248
// print(f"Network error: {e}")
249
```
250
251
### Exception Translation with Custom Behavior
252
253
```cpp
254
#include <pybind11/pybind11.h>
255
256
namespace py = pybind11;
257
258
// Custom exception with additional data
259
class ValidationError : public std::exception {
260
public:
261
ValidationError(const std::string& field, const std::string& message)
262
: field_(field), message_(message) {}
263
264
const char* what() const noexcept override { return message_.c_str(); }
265
const std::string& field() const { return field_; }
266
const std::string& message() const { return message_; }
267
268
private:
269
std::string field_;
270
std::string message_;
271
};
272
273
void validate_data(const std::string& email) {
274
if (email.find('@') == std::string::npos) {
275
throw ValidationError("email", "Invalid email format");
276
}
277
}
278
279
PYBIND11_MODULE(example, m) {
280
// Register with custom translator
281
auto validation_error = py::register_exception<ValidationError>(m, "ValidationError");
282
283
// Set custom translator to include field information
284
validation_error.set_translator([](const ValidationError& e) {
285
PyErr_SetString(PyExc_ValueError,
286
("Validation error in field '" + e.field() + "': " + e.message()).c_str());
287
});
288
289
m.def("validate_data", &validate_data);
290
}
291
```
292
293
### Handling Python Exceptions in C++
294
295
```cpp
296
#include <pybind11/pybind11.h>
297
298
namespace py = pybind11;
299
300
void call_python_function(py::function func, py::object arg) {
301
try {
302
// Call Python function that might raise an exception
303
py::object result = func(arg);
304
std::cout << "Result: " << py::str(result) << std::endl;
305
}
306
catch (py::error_already_set &e) {
307
// Handle Python exception in C++
308
std::cout << "Python exception caught: " << e.what() << std::endl;
309
310
// Check exception type
311
if (e.matches(PyExc_ValueError)) {
312
std::cout << "It was a ValueError" << std::endl;
313
}
314
315
// Re-raise the exception to Python
316
e.restore();
317
throw;
318
}
319
}
320
321
PYBIND11_MODULE(example, m) {
322
m.def("call_python_function", &call_python_function);
323
}
324
```
325
326
### Exception Context Management
327
328
```cpp
329
#include <pybind11/pybind11.h>
330
331
namespace py = pybind11;
332
333
py::object safe_python_call(py::function func) {
334
py::error_scope scope; // Automatically manages error state
335
336
try {
337
return func();
338
}
339
catch (...) {
340
if (scope.has_error()) {
341
// Handle any Python errors that occurred
342
auto error = scope.get_error();
343
std::cout << "Error during call: " << error.what() << std::endl;
344
throw;
345
}
346
// Handle C++ exceptions
347
throw;
348
}
349
}
350
351
PYBIND11_MODULE(example, m) {
352
m.def("safe_python_call", &safe_python_call);
353
}
354
```
355
356
### Iterator Exception Handling
357
358
```cpp
359
#include <pybind11/pybind11.h>
360
361
namespace py = pybind11;
362
363
class NumberIterator {
364
int current_, max_;
365
public:
366
NumberIterator(int max) : current_(0), max_(max) {}
367
368
NumberIterator& iter() { return *this; }
369
370
int next() {
371
if (current_ >= max_) {
372
// Proper way to signal iteration end
373
throw py::stop_iteration();
374
}
375
return current_++;
376
}
377
};
378
379
PYBIND11_MODULE(example, m) {
380
py::class_<NumberIterator>(m, "NumberIterator")
381
.def(py::init<int>())
382
.def("__iter__", &NumberIterator::iter,
383
py::return_value_policy::reference_internal)
384
.def("__next__", &NumberIterator::next);
385
}
386
```
387
388
### Exception Chaining
389
390
```cpp
391
#include <pybind11/pybind11.h>
392
393
namespace py = pybind11;
394
395
void process_file(const std::string& filename) {
396
try {
397
// Simulate file processing that might fail
398
if (filename.empty()) {
399
throw std::invalid_argument("Filename cannot be empty");
400
}
401
402
// Simulate I/O error
403
throw std::runtime_error("File not found: " + filename);
404
}
405
catch (const std::invalid_argument& e) {
406
// Chain exceptions
407
throw std::runtime_error("Failed to process file: " + std::string(e.what()));
408
}
409
}
410
411
PYBIND11_MODULE(example, m) {
412
m.def("process_file", &process_file);
413
}
414
```
415
416
## Error Handling Best Practices
417
418
### Resource Management with Exceptions
419
420
```cpp
421
#include <pybind11/pybind11.h>
422
#include <memory>
423
424
namespace py = pybind11;
425
426
class Resource {
427
public:
428
Resource() { /* acquire resource */ }
429
~Resource() { /* release resource */ }
430
431
void use() {
432
// Might throw an exception
433
throw std::runtime_error("Resource error");
434
}
435
};
436
437
void use_resource() {
438
// Use RAII for exception safety
439
auto resource = std::make_unique<Resource>();
440
441
try {
442
resource->use();
443
}
444
catch (...) {
445
// Resource automatically cleaned up by unique_ptr
446
throw;
447
}
448
}
449
450
PYBIND11_MODULE(example, m) {
451
m.def("use_resource", &use_resource);
452
}
453
```
454
455
## Types
456
457
```cpp { .api }
458
namespace pybind11 {
459
// Exception handling classes
460
class error_already_set;
461
class builtin_exception;
462
class cast_error;
463
class reference_cast_error;
464
465
// Built-in Python exception wrappers
466
class stop_iteration;
467
class index_error;
468
class key_error;
469
class value_error;
470
class type_error;
471
class attribute_error;
472
473
// Custom exception registration
474
template<typename CppException> class exception;
475
476
// Utility classes
477
class error_scope;
478
479
// Exception registration functions
480
template<typename CppException>
481
exception<CppException>& register_exception(module_ &m, const char *name, handle base);
482
483
template<typename CppException>
484
void register_exception_translator(std::function<void(const CppException&)> translator);
485
}
486
```