Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/azure/core/exceptions.py: 33%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

221 statements  

1# -------------------------------------------------------------------------- 

2# 

3# Copyright (c) Microsoft Corporation. All rights reserved. 

4# 

5# The MIT License (MIT) 

6# 

7# Permission is hereby granted, free of charge, to any person obtaining a copy 

8# of this software and associated documentation files (the ""Software""), to 

9# deal in the Software without restriction, including without limitation the 

10# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 

11# sell copies of the Software, and to permit persons to whom the Software is 

12# furnished to do so, subject to the following conditions: 

13# 

14# The above copyright notice and this permission notice shall be included in 

15# all copies or substantial portions of the Software. 

16# 

17# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 

18# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 

19# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 

20# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 

21# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 

22# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 

23# IN THE SOFTWARE. 

24# 

25# -------------------------------------------------------------------------- 

26from __future__ import annotations 

27import json 

28import logging 

29import sys 

30 

31from types import TracebackType 

32from typing import ( 

33 Callable, 

34 Any, 

35 Optional, 

36 Union, 

37 Type, 

38 List, 

39 Mapping, 

40 TypeVar, 

41 Generic, 

42 Dict, 

43 NoReturn, 

44 TYPE_CHECKING, 

45) 

46from typing_extensions import Protocol, runtime_checkable 

47 

48_LOGGER = logging.getLogger(__name__) 

49 

50if TYPE_CHECKING: 

51 from azure.core.pipeline.policies import RequestHistory 

52 

53HTTPResponseType = TypeVar("HTTPResponseType") 

54HTTPRequestType = TypeVar("HTTPRequestType") 

55KeyType = TypeVar("KeyType") 

56ValueType = TypeVar("ValueType") 

57# To replace when typing.Self is available in our baseline 

58SelfODataV4Format = TypeVar("SelfODataV4Format", bound="ODataV4Format") 

59 

60 

61__all__ = [ 

62 "AzureError", 

63 "ServiceRequestError", 

64 "ServiceResponseError", 

65 "HttpResponseError", 

66 "DecodeError", 

67 "ResourceExistsError", 

68 "ResourceNotFoundError", 

69 "ClientAuthenticationError", 

70 "ResourceModifiedError", 

71 "ResourceNotModifiedError", 

72 "TooManyRedirectsError", 

73 "ODataV4Format", 

74 "ODataV4Error", 

75 "StreamConsumedError", 

76 "StreamClosedError", 

77 "ResponseNotReadError", 

78 "SerializationError", 

79 "DeserializationError", 

80] 

81 

82 

83def raise_with_traceback(exception: Callable, *args: Any, message: str = "", **kwargs: Any) -> NoReturn: 

84 """Raise exception with a specified traceback. 

85 This MUST be called inside a "except" clause. 

86 

87 .. note:: This method is deprecated since we don't support Python 2 anymore. Use raise/from instead. 

88 

89 :param Exception exception: Error type to be raised. 

90 :param any args: Any additional args to be included with exception. 

91 :keyword str message: Message to be associated with the exception. If omitted, defaults to an empty string. 

92 """ 

93 exc_type, exc_value, exc_traceback = sys.exc_info() 

94 # If not called inside an "except", exc_type will be None. Assume it will not happen 

95 if exc_type is None: 

96 raise ValueError("raise_with_traceback can only be used in except clauses") 

97 exc_msg = "{}, {}: {}".format(message, exc_type.__name__, exc_value) 

98 error = exception(exc_msg, *args, **kwargs) 

99 try: 

100 raise error.with_traceback(exc_traceback) 

101 except AttributeError: # Python 2 

102 error.__traceback__ = exc_traceback 

103 raise error # pylint: disable=raise-missing-from 

104 

105 

106@runtime_checkable 

107class _HttpResponseCommonAPI(Protocol): 

108 """Protocol used by exceptions for HTTP response. 

109 

110 As HttpResponseError uses very few properties of HttpResponse, a protocol 

111 is faster and simpler than import all the possible types (at least 6). 

112 """ 

113 

114 @property 

115 def reason(self) -> Optional[str]: ... 

116 

117 @property 

118 def status_code(self) -> Optional[int]: ... 

119 

120 def text(self) -> str: ... 

121 

122 @property 

123 def request(self) -> object: # object as type, since all we need is str() on it 

124 ... 

125 

126 

127class ErrorMap(Generic[KeyType, ValueType]): 

128 """Error Map class. To be used in map_error method, behaves like a dictionary. 

129 It returns the error type if it is found in custom_error_map. Or return default_error 

130 

131 :param dict custom_error_map: User-defined error map, it is used to map status codes to error types. 

132 :keyword error default_error: Default error type. It is returned if the status code is not found in custom_error_map 

133 """ 

134 

135 def __init__( 

136 self, # pylint: disable=unused-argument 

137 custom_error_map: Optional[Mapping[KeyType, ValueType]] = None, 

138 *, 

139 default_error: Optional[ValueType] = None, 

140 **kwargs: Any, 

141 ) -> None: 

142 self._custom_error_map = custom_error_map or {} 

143 self._default_error = default_error 

144 

145 def get(self, key: KeyType) -> Optional[ValueType]: 

146 ret = self._custom_error_map.get(key) 

147 if ret: 

148 return ret 

149 return self._default_error 

150 

151 

152def map_error( 

153 status_code: int, 

154 response: _HttpResponseCommonAPI, 

155 error_map: Mapping[int, Type[HttpResponseError]], 

156) -> None: 

157 if not error_map: 

158 return 

159 error_type = error_map.get(status_code) 

160 if not error_type: 

161 return 

162 error = error_type(response=response) 

163 raise error 

164 

165 

166class ODataV4Format: 

167 """Class to describe OData V4 error format. 

168 

169 http://docs.oasis-open.org/odata/odata-json-format/v4.0/os/odata-json-format-v4.0-os.html#_Toc372793091 

170 

171 Example of JSON: 

172 

173 .. code-block:: json 

174 

175 { 

176 "error": { 

177 "code": "ValidationError", 

178 "message": "One or more fields contain incorrect values: ", 

179 "details": [ 

180 { 

181 "code": "ValidationError", 

182 "target": "representation", 

183 "message": "Parsing error(s): String '' does not match regex pattern '^[^{}/ :]+(?: :\\\\d+)?$'. 

184 Path 'host', line 1, position 297." 

185 }, 

186 { 

187 "code": "ValidationError", 

188 "target": "representation", 

189 "message": "Parsing error(s): The input OpenAPI file is not valid for the OpenAPI specificate 

190 https: //github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md 

191 (schema https://github.com/OAI/OpenAPI-Specification/blob/master/schemas/v2.0/schema.json)." 

192 } 

193 ] 

194 } 

195 } 

196 

197 :param dict json_object: A Python dict representing a ODataV4 JSON 

198 :ivar str code: Its value is a service-defined error code. 

199 This code serves as a sub-status for the HTTP error code specified in the response. 

200 :ivar str message: Human-readable, language-dependent representation of the error. 

201 :ivar str target: The target of the particular error (for example, the name of the property in error). 

202 This field is optional and may be None. 

203 :ivar list[ODataV4Format] details: Array of ODataV4Format instances that MUST contain name/value pairs 

204 for code and message, and MAY contain a name/value pair for target, as described above. 

205 :ivar dict innererror: An object. The contents of this object are service-defined. 

206 Usually this object contains information that will help debug the service. 

207 """ 

208 

209 CODE_LABEL = "code" 

210 MESSAGE_LABEL = "message" 

211 TARGET_LABEL = "target" 

212 DETAILS_LABEL = "details" 

213 INNERERROR_LABEL = "innererror" 

214 

215 def __init__(self, json_object: Mapping[str, Any]) -> None: 

216 if "error" in json_object: 

217 json_object = json_object["error"] 

218 cls: Type[ODataV4Format] = self.__class__ 

219 

220 # Required fields, but assume they could be missing still to be robust 

221 self.code: Optional[str] = json_object.get(cls.CODE_LABEL) 

222 self.message: Optional[str] = json_object.get(cls.MESSAGE_LABEL) 

223 

224 if not (self.code or self.message): 

225 raise ValueError("Impossible to extract code/message from received JSON:\n" + json.dumps(json_object)) 

226 

227 # Optional fields 

228 self.target: Optional[str] = json_object.get(cls.TARGET_LABEL) 

229 

230 # details is recursive of this very format 

231 self.details: List[ODataV4Format] = [] 

232 for detail_node in json_object.get(cls.DETAILS_LABEL) or []: 

233 try: 

234 self.details.append(self.__class__(detail_node)) 

235 except Exception: # pylint: disable=broad-except 

236 pass 

237 

238 self.innererror: Mapping[str, Any] = json_object.get(cls.INNERERROR_LABEL, {}) 

239 

240 def as_dict(self, *, exclude_readonly: bool = False) -> Dict[str, Any]: 

241 """Return the parsed error as a JSON-compatible dictionary. 

242 

243 :keyword bool exclude_readonly: Whether to exclude readonly fields. 

244 :return: A dictionary representing the error. 

245 :rtype: dict[str, Any] 

246 """ 

247 

248 def as_dict_value(value: Any) -> Any: 

249 as_dict = getattr(value, "as_dict", None) 

250 if callable(as_dict): 

251 return as_dict(exclude_readonly=exclude_readonly) 

252 if isinstance(value, Mapping): 

253 return {key: as_dict_value(item) for key, item in value.items()} 

254 if isinstance(value, list): 

255 return [as_dict_value(item) for item in value] 

256 return value 

257 

258 return { 

259 self.CODE_LABEL: self.code, 

260 self.MESSAGE_LABEL: self.message, 

261 self.TARGET_LABEL: self.target, 

262 self.DETAILS_LABEL: as_dict_value(self.details), 

263 self.INNERERROR_LABEL: as_dict_value(self.innererror), 

264 } 

265 

266 @property 

267 def error(self: SelfODataV4Format) -> SelfODataV4Format: 

268 import warnings 

269 

270 warnings.warn( 

271 "error.error from azure exceptions is deprecated, just simply use 'error' once", 

272 DeprecationWarning, 

273 ) 

274 return self 

275 

276 def __str__(self) -> str: 

277 return "({}) {}\n{}".format(self.code, self.message, self.message_details()) 

278 

279 def message_details(self) -> str: 

280 """Return a detailed string of the error. 

281 

282 :return: A string with the details of the error. 

283 :rtype: str 

284 """ 

285 error_str = "Code: {}".format(self.code) 

286 error_str += "\nMessage: {}".format(self.message) 

287 if self.target: 

288 error_str += "\nTarget: {}".format(self.target) 

289 

290 if self.details: 

291 error_str += "\nException Details:" 

292 for error_obj in self.details: 

293 # Indent for visibility 

294 error_str += "\n".join("\t" + s for s in str(error_obj).splitlines()) 

295 

296 if self.innererror: 

297 error_str += "\nInner error: {}".format(json.dumps(self.innererror, indent=4)) 

298 return error_str 

299 

300 

301class AzureError(Exception): 

302 """Base exception for all errors. 

303 

304 :param object message: The message object stringified as 'message' attribute 

305 :keyword error: The original exception if any 

306 :paramtype error: Exception 

307 

308 :ivar inner_exception: The exception passed with the 'error' kwarg 

309 :vartype inner_exception: Exception 

310 :ivar exc_type: The exc_type from sys.exc_info() 

311 :ivar exc_value: The exc_value from sys.exc_info() 

312 :ivar exc_traceback: The exc_traceback from sys.exc_info() 

313 :ivar exc_msg: A string formatting of message parameter, exc_type and exc_value 

314 :ivar str message: A stringified version of the message parameter 

315 :ivar str continuation_token: A token reference to continue an incomplete operation. This value is optional 

316 and will be `None` where continuation is either unavailable or not applicable. 

317 """ 

318 

319 def __init__(self, message: Optional[object], *args: Any, **kwargs: Any) -> None: 

320 self.inner_exception: Optional[BaseException] = kwargs.get("error") 

321 

322 exc_info = sys.exc_info() 

323 self.exc_type: Optional[Type[Any]] = exc_info[0] 

324 self.exc_value: Optional[BaseException] = exc_info[1] 

325 self.exc_traceback: Optional[TracebackType] = exc_info[2] 

326 

327 self.exc_type = self.exc_type if self.exc_type else type(self.inner_exception) 

328 self.exc_msg: str = "{}, {}: {}".format(message, self.exc_type.__name__, self.exc_value) 

329 self.message: str = str(message) 

330 self.continuation_token: Optional[str] = kwargs.get("continuation_token") 

331 super(AzureError, self).__init__(self.message, *args) 

332 

333 def raise_with_traceback(self) -> None: 

334 """Raise the exception with the existing traceback. 

335 

336 .. deprecated:: 1.22.0 

337 This method is deprecated as we don't support Python 2 anymore. Use raise/from instead. 

338 """ 

339 try: 

340 raise super(AzureError, self).with_traceback(self.exc_traceback) 

341 except AttributeError: 

342 self.__traceback__: Optional[TracebackType] = self.exc_traceback 

343 raise self # pylint: disable=raise-missing-from 

344 

345 

346class ServiceRequestError(AzureError): 

347 """An error occurred while attempt to make a request to the service. 

348 No request was sent. 

349 """ 

350 

351 

352class ServiceResponseError(AzureError): 

353 """The request was sent, but the client failed to understand the response. 

354 The connection may have timed out. These errors can be retried for idempotent or 

355 safe operations""" 

356 

357 

358class ServiceRequestTimeoutError(ServiceRequestError): 

359 """Error raised when timeout happens""" 

360 

361 

362class ServiceResponseTimeoutError(ServiceResponseError): 

363 """Error raised when timeout happens""" 

364 

365 

366class HttpResponseError(AzureError): 

367 """A request was made, and a non-success status code was received from the service. 

368 

369 :param object message: The message object stringified as 'message' attribute 

370 :param response: The response that triggered the exception. 

371 :type response: ~azure.core.pipeline.transport.HttpResponse or ~azure.core.pipeline.transport.AsyncHttpResponse 

372 

373 :ivar reason: The HTTP response reason 

374 :vartype reason: str 

375 :ivar status_code: HttpResponse's status code 

376 :vartype status_code: int 

377 :ivar response: The response that triggered the exception. 

378 :vartype response: ~azure.core.pipeline.transport.HttpResponse or ~azure.core.pipeline.transport.AsyncHttpResponse 

379 :ivar model: The request body/response body model 

380 :vartype model: ~msrest.serialization.Model 

381 :ivar error: The formatted error 

382 :vartype error: ODataV4Format 

383 """ 

384 

385 def __init__( 

386 self, 

387 message: Optional[object] = None, 

388 response: Optional[_HttpResponseCommonAPI] = None, 

389 **kwargs: Any, 

390 ) -> None: 

391 # Don't want to document this one yet. 

392 error_format = kwargs.get("error_format", ODataV4Format) 

393 

394 self.reason: Optional[str] = None 

395 self.status_code: Optional[int] = None 

396 self.response: Optional[_HttpResponseCommonAPI] = response 

397 if response: 

398 self.reason = response.reason 

399 self.status_code = response.status_code 

400 

401 # old autorest are setting "error" before calling __init__, so it might be there already 

402 # transferring into self.model 

403 model: Optional[Any] = kwargs.pop("model", None) 

404 self.model: Optional[Any] 

405 if model is not None: # autorest v5 

406 self.model = model 

407 else: # autorest azure-core, for KV 1.0, Storage 12.0, etc. 

408 self.model = getattr(self, "error", None) 

409 self.error: Optional[ODataV4Format] = self._parse_odata_body(error_format, response) 

410 

411 # By priority, message is: 

412 # - odatav4 message, OR 

413 # - parameter "message", OR 

414 # - generic meassage using "reason" 

415 if self.error: 

416 message = str(self.error) 

417 else: 

418 message = message or "Operation returned an invalid status '{}'".format(self.reason) 

419 

420 super(HttpResponseError, self).__init__(message=message, **kwargs) 

421 

422 @staticmethod 

423 def _parse_odata_body( 

424 error_format: Type[ODataV4Format], response: Optional[_HttpResponseCommonAPI] 

425 ) -> Optional[ODataV4Format]: 

426 try: 

427 # https://github.com/python/mypy/issues/14743#issuecomment-1664725053 

428 odata_json = json.loads(response.text()) # type: ignore 

429 return error_format(odata_json) 

430 except Exception: # pylint: disable=broad-except 

431 # If the body is not JSON valid, just stop now 

432 pass 

433 return None 

434 

435 def __str__(self) -> str: 

436 retval = super(HttpResponseError, self).__str__() 

437 try: 

438 # https://github.com/python/mypy/issues/14743#issuecomment-1664725053 

439 body = self.response.text() # type: ignore 

440 if body and not self.error: 

441 return "{}\nContent: {}".format(retval, body)[:2048] 

442 except Exception: # pylint: disable=broad-except 

443 pass 

444 return retval 

445 

446 

447class DecodeError(HttpResponseError): 

448 """Error raised during response deserialization.""" 

449 

450 

451class IncompleteReadError(DecodeError): 

452 """Error raised if peer closes the connection before we have received the complete message body.""" 

453 

454 

455class ResourceExistsError(HttpResponseError): 

456 """An error response with status code 4xx. 

457 This will not be raised directly by the Azure core pipeline.""" 

458 

459 

460class ResourceNotFoundError(HttpResponseError): 

461 """An error response, typically triggered by a 412 response (for update) or 404 (for get/post)""" 

462 

463 

464class ClientAuthenticationError(HttpResponseError): 

465 """An error response with status code 4xx. 

466 This will not be raised directly by the Azure core pipeline.""" 

467 

468 

469class ResourceModifiedError(HttpResponseError): 

470 """An error response with status code 4xx, typically 412 Conflict. 

471 This will not be raised directly by the Azure core pipeline.""" 

472 

473 

474class ResourceNotModifiedError(HttpResponseError): 

475 """An error response with status code 304. 

476 This will not be raised directly by the Azure core pipeline.""" 

477 

478 

479class TooManyRedirectsError(HttpResponseError, Generic[HTTPRequestType, HTTPResponseType]): 

480 """Reached the maximum number of redirect attempts. 

481 

482 :param history: The history of requests made while trying to fulfill the request. 

483 :type history: list[~azure.core.pipeline.policies.RequestHistory] 

484 """ 

485 

486 def __init__( 

487 self, 

488 history: "List[RequestHistory[HTTPRequestType, HTTPResponseType]]", 

489 *args: Any, 

490 **kwargs: Any, 

491 ) -> None: 

492 self.history = history 

493 message = "Reached maximum redirect attempts." 

494 super(TooManyRedirectsError, self).__init__(message, *args, **kwargs) 

495 

496 

497class ODataV4Error(HttpResponseError): 

498 """An HTTP response error where the JSON is decoded as OData V4 error format. 

499 

500 http://docs.oasis-open.org/odata/odata-json-format/v4.0/os/odata-json-format-v4.0-os.html#_Toc372793091 

501 

502 :param ~azure.core.rest.HttpResponse response: The response object. 

503 :ivar dict odata_json: The parsed JSON body as attribute for convenience. 

504 :ivar str ~.code: Its value is a service-defined error code. 

505 This code serves as a sub-status for the HTTP error code specified in the response. 

506 :ivar str message: Human-readable, language-dependent representation of the error. 

507 :ivar str target: The target of the particular error (for example, the name of the property in error). 

508 This field is optional and may be None. 

509 :ivar list[ODataV4Format] details: Array of ODataV4Format instances that MUST contain name/value pairs 

510 for code and message, and MAY contain a name/value pair for target, as described above. 

511 :ivar dict innererror: An object. The contents of this object are service-defined. 

512 Usually this object contains information that will help debug the service. 

513 """ 

514 

515 _ERROR_FORMAT = ODataV4Format 

516 

517 def __init__(self, response: _HttpResponseCommonAPI, **kwargs: Any) -> None: 

518 # Ensure field are declared, whatever can happen afterwards 

519 self.odata_json: Optional[Dict[str, Any]] = None 

520 try: 

521 self.odata_json = json.loads(response.text()) 

522 odata_message = self.odata_json.setdefault("error", {}).get("message") 

523 except Exception: # pylint: disable=broad-except 

524 # If the body is not JSON valid, just stop now 

525 odata_message = None 

526 

527 self.code: Optional[str] = None 

528 message: Optional[str] = kwargs.get("message", odata_message) 

529 self.target: Optional[str] = None 

530 self.details: Optional[List[Any]] = [] 

531 self.innererror: Optional[Mapping[str, Any]] = {} 

532 

533 if message and "message" not in kwargs: 

534 kwargs["message"] = message 

535 

536 super(ODataV4Error, self).__init__(response=response, **kwargs) 

537 

538 self._error_format: Optional[Union[str, ODataV4Format]] = None 

539 if self.odata_json: 

540 try: 

541 error_node = self.odata_json["error"] 

542 self._error_format = self._ERROR_FORMAT(error_node) 

543 self.__dict__.update({k: v for k, v in self._error_format.__dict__.items() if v is not None}) 

544 except Exception: # pylint: disable=broad-except 

545 _LOGGER.info("Received error message was not valid OdataV4 format.") 

546 self._error_format = "JSON was invalid for format " + str(self._ERROR_FORMAT) 

547 

548 def __str__(self) -> str: 

549 if self._error_format: 

550 return str(self._error_format) 

551 return super(ODataV4Error, self).__str__() 

552 

553 

554class StreamConsumedError(AzureError): 

555 """Error thrown if you try to access the stream of a response once consumed. 

556 

557 It is thrown if you try to read / stream an ~azure.core.rest.HttpResponse or 

558 ~azure.core.rest.AsyncHttpResponse once the response's stream has been consumed. 

559 

560 :param response: The response that triggered the exception. 

561 :type response: ~azure.core.rest.HttpResponse or ~azure.core.rest.AsyncHttpResponse 

562 """ 

563 

564 def __init__(self, response: _HttpResponseCommonAPI) -> None: 

565 message = ( 

566 "You are attempting to read or stream the content from request {}. " 

567 "You have likely already consumed this stream, so it can not be accessed anymore.".format(response.request) 

568 ) 

569 super(StreamConsumedError, self).__init__(message) 

570 

571 

572class StreamClosedError(AzureError): 

573 """Error thrown if you try to access the stream of a response once closed. 

574 

575 It is thrown if you try to read / stream an ~azure.core.rest.HttpResponse or 

576 ~azure.core.rest.AsyncHttpResponse once the response's stream has been closed. 

577 

578 :param response: The response that triggered the exception. 

579 :type response: ~azure.core.rest.HttpResponse or ~azure.core.rest.AsyncHttpResponse 

580 """ 

581 

582 def __init__(self, response: _HttpResponseCommonAPI) -> None: 

583 message = ( 

584 "The content for response from request {} can no longer be read or streamed, since the " 

585 "response has already been closed.".format(response.request) 

586 ) 

587 super(StreamClosedError, self).__init__(message) 

588 

589 

590class ResponseNotReadError(AzureError): 

591 """Error thrown if you try to access a response's content without reading first. 

592 

593 It is thrown if you try to access an ~azure.core.rest.HttpResponse or 

594 ~azure.core.rest.AsyncHttpResponse's content without first reading the response's bytes in first. 

595 

596 :param response: The response that triggered the exception. 

597 :type response: ~azure.core.rest.HttpResponse or ~azure.core.rest.AsyncHttpResponse 

598 """ 

599 

600 def __init__(self, response: _HttpResponseCommonAPI) -> None: 

601 message = ( 

602 "You have not read in the bytes for the response from request {}. " 

603 "Call .read() on the response first.".format(response.request) 

604 ) 

605 super(ResponseNotReadError, self).__init__(message) 

606 

607 

608class SerializationError(ValueError): 

609 """Raised if an error is encountered during serialization.""" 

610 

611 

612class DeserializationError(ValueError): 

613 """Raised if an error is encountered during deserialization."""