0
# Error Handling
1
2
Comprehensive error hierarchy for serialization, deserialization, and cryptographic operation failures with detailed error information for debugging and error recovery.
3
4
## Capabilities
5
6
### Base Error Class
7
8
Root exception class for all JOSE-related errors.
9
10
```python { .api }
11
class Error(Exception):
12
"""
13
Generic JOSE Error.
14
15
Base class for all JOSE-related exceptions. Inherit from this
16
class when creating custom JOSE error types.
17
"""
18
```
19
20
### Serialization Errors
21
22
Errors that occur during JSON serialization operations.
23
24
```python { .api }
25
class SerializationError(Error):
26
"""
27
JSON serialization error.
28
29
Raised when an object cannot be serialized to JSON format,
30
typically due to unsupported data types or circular references.
31
"""
32
```
33
34
### Deserialization Errors
35
36
Errors that occur during JSON deserialization and data validation.
37
38
```python { .api }
39
class DeserializationError(Error):
40
"""
41
JSON deserialization error.
42
43
Raised when JSON data cannot be parsed or converted to the
44
expected object type. Common causes include:
45
- Invalid JSON structure
46
- Missing required fields
47
- Type conversion failures
48
- Size validation failures
49
"""
50
51
def __str__(self) -> str:
52
"""Returns formatted error message with 'Deserialization error:' prefix"""
53
```
54
55
### Type Recognition Errors
56
57
Specialized deserialization error for unknown or unsupported object types.
58
59
```python { .api }
60
class UnrecognizedTypeError(DeserializationError):
61
"""
62
Unrecognized type error.
63
64
Raised when attempting to deserialize a JSON object with an
65
unknown or unsupported type identifier.
66
"""
67
68
def __init__(self, typ: str, jobj: Any) -> None:
69
"""
70
Initialize with type information.
71
72
Parameters:
73
- typ: The unrecognized type identifier
74
- jobj: Full JSON object that caused the error
75
"""
76
77
def __str__(self) -> str:
78
"""Returns detailed error message with type and full object"""
79
80
typ: str # The unrecognized type identifier
81
jobj: Any # Full JSON object
82
```
83
84
## Usage Examples
85
86
### Basic Error Handling
87
88
```python
89
from josepy import JWS, JWKRSA, RS256
90
from josepy.errors import Error, DeserializationError, SerializationError
91
92
try:
93
# Attempt to load invalid JWS
94
jws = JWS.json_loads('{"invalid": "jws_structure"}')
95
except DeserializationError as e:
96
print(f"Failed to parse JWS: {e}")
97
# Handle invalid input gracefully
98
99
try:
100
# Attempt signature verification with wrong key
101
payload = jws.verify(wrong_key)
102
except Error as e:
103
print(f"Signature verification failed: {e}")
104
# Handle authentication failure
105
```
106
107
### Specific Error Type Handling
108
109
```python
110
from josepy import JWK
111
from josepy.errors import UnrecognizedTypeError, DeserializationError
112
113
# Example JSON with unknown key type
114
unknown_jwk_json = '''
115
{
116
"kty": "unknown_key_type",
117
"use": "sig",
118
"n": "...",
119
"e": "AQAB"
120
}
121
'''
122
123
try:
124
jwk = JWK.json_loads(unknown_jwk_json)
125
except UnrecognizedTypeError as e:
126
print(f"Unknown key type: {e.typ}")
127
print(f"Full object: {e.jobj}")
128
# Could fall back to a different key handling strategy
129
130
except DeserializationError as e:
131
print(f"General deserialization error: {e}")
132
# Handle other parsing issues
133
```
134
135
### Error Context and Debugging
136
137
```python
138
import json
139
from josepy import JWKRSA
140
from josepy.errors import DeserializationError
141
142
# Detailed error handling with context
143
def safe_jwk_load(jwk_data: str) -> Optional[JWKRSA]:
144
try:
145
# First validate JSON structure
146
json_obj = json.loads(jwk_data)
147
148
# Then attempt JWK deserialization
149
return JWKRSA.json_loads(jwk_data)
150
151
except json.JSONDecodeError as e:
152
print(f"Invalid JSON at line {e.lineno}, column {e.colno}: {e.msg}")
153
return None
154
155
except DeserializationError as e:
156
print(f"JWK deserialization failed: {e}")
157
print(f"Input data: {jwk_data[:100]}..." if len(jwk_data) > 100 else jwk_data)
158
return None
159
160
except Exception as e:
161
print(f"Unexpected error: {type(e).__name__}: {e}")
162
return None
163
164
# Usage
165
jwk = safe_jwk_load(potentially_invalid_jwk_json)
166
if jwk is None:
167
print("Failed to load JWK, using default key")
168
jwk = get_default_key()
169
```
170
171
### Cryptographic Error Integration
172
173
```python
174
import cryptography.exceptions
175
from josepy import RS256, JWKRSA
176
from josepy.errors import Error
177
178
def safe_sign_and_verify(message: bytes, jwk: JWKRSA) -> bool:
179
try:
180
# Sign message
181
signature = RS256.sign(jwk.key, message)
182
183
# Verify signature
184
is_valid = RS256.verify(jwk.public_key().key, message, signature)
185
return is_valid
186
187
except cryptography.exceptions.InvalidSignature:
188
print("Cryptographic signature operation failed")
189
return False
190
191
except Error as e:
192
print(f"JOSE operation failed: {e}")
193
return False
194
195
except Exception as e:
196
print(f"Unexpected error: {e}")
197
return False
198
199
# Usage
200
success = safe_sign_and_verify(b"test message", my_jwk)
201
print(f"Signature test: {'PASSED' if success else 'FAILED'}")
202
```
203
204
### Error Recovery Strategies
205
206
```python
207
from josepy import JWK, JWKRSA, JWKEC, JWKOct
208
from josepy.errors import UnrecognizedTypeError, DeserializationError
209
210
def robust_jwk_loader(jwk_json: str) -> Optional[JWK]:
211
"""
212
Attempt to load JWK with multiple fallback strategies.
213
"""
214
try:
215
# First try generic JWK loading
216
return JWK.from_json(json.loads(jwk_json))
217
218
except UnrecognizedTypeError as e:
219
print(f"Unknown key type '{e.typ}', trying specific loaders...")
220
221
# Try specific key types as fallbacks
222
json_obj = e.jobj
223
224
if json_obj.get('kty') == 'RSA':
225
try:
226
return JWKRSA.from_json(json_obj)
227
except DeserializationError:
228
pass
229
230
elif json_obj.get('kty') == 'EC':
231
try:
232
return JWKEC.from_json(json_obj)
233
except DeserializationError:
234
pass
235
236
elif json_obj.get('kty') == 'oct':
237
try:
238
return JWKOct.from_json(json_obj)
239
except DeserializationError:
240
pass
241
242
print("All fallback strategies failed")
243
return None
244
245
except DeserializationError as e:
246
print(f"Deserialization failed: {e}")
247
return None
248
249
# Usage with graceful degradation
250
jwk = robust_jwk_loader(received_jwk_json)
251
if jwk is None:
252
print("Using fallback authentication method")
253
# Implement alternative authentication
254
```
255
256
### Logging and Monitoring
257
258
```python
259
import logging
260
from josepy.errors import Error, DeserializationError, SerializationError
261
262
# Configure logging for JOSE operations
263
logger = logging.getLogger('josepy_operations')
264
265
def logged_jws_operation(operation_name: str, operation_func, *args, **kwargs):
266
"""Wrapper for JWS operations with comprehensive logging."""
267
try:
268
logger.info(f"Starting {operation_name}")
269
result = operation_func(*args, **kwargs)
270
logger.info(f"Successfully completed {operation_name}")
271
return result
272
273
except DeserializationError as e:
274
logger.error(f"{operation_name} deserialization failed: {e}")
275
raise
276
277
except SerializationError as e:
278
logger.error(f"{operation_name} serialization failed: {e}")
279
raise
280
281
except Error as e:
282
logger.error(f"{operation_name} JOSE error: {e}")
283
raise
284
285
except Exception as e:
286
logger.critical(f"{operation_name} unexpected error: {type(e).__name__}: {e}")
287
raise
288
289
# Usage
290
try:
291
jws = logged_jws_operation("JWS creation", JWS.sign, payload, key=jwk, alg=RS256)
292
verified = logged_jws_operation("JWS verification", jws.verify, public_jwk)
293
except Error:
294
# Handle JOSE-specific errors
295
handle_jose_error()
296
```
297
298
## Error Classification
299
300
### By Origin
301
- **Input Validation**: DeserializationError, UnrecognizedTypeError
302
- **Output Generation**: SerializationError
303
- **Cryptographic Operations**: Error (with underlying cryptography exceptions)
304
- **Generic JOSE**: Error (base class)
305
306
### By Severity
307
- **Critical**: Cryptographic signature failures (security implications)
308
- **High**: Type recognition failures (compatibility issues)
309
- **Medium**: General deserialization failures (data quality issues)
310
- **Low**: Serialization failures (output formatting issues)
311
312
### By Recovery Strategy
313
- **Retryable**: Temporary network or resource issues
314
- **Fallback**: Alternative algorithms or key types available
315
- **Abort**: Security violations or critical data corruption
316
- **Graceful**: Continue with reduced functionality
317
318
## Best Practices
319
320
1. **Catch Specific Exceptions**: Handle UnrecognizedTypeError differently from general DeserializationError
321
2. **Preserve Error Context**: Log full error messages and relevant data for debugging
322
3. **Implement Fallbacks**: Design systems to gracefully handle unknown key types or algorithms
323
4. **Security First**: Treat cryptographic errors as security events requiring careful handling
324
5. **User-Friendly Messages**: Convert technical error messages to user-appropriate language
325
6. **Monitoring**: Track error patterns to identify systemic issues or attack attempts