1# Copyright 2015 The TensorFlow Authors. All Rights Reserved. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14# ============================================================================== 15"""Exception types for TensorFlow errors.""" 16 17import traceback 18import warnings 19 20from tensorflow.core.lib.core import error_codes_pb2 21from tensorflow.python import _pywrap_py_exception_registry 22from tensorflow.python.client import pywrap_tf_session as c_api 23from tensorflow.python.framework import c_api_util 24from tensorflow.python.util import compat 25from tensorflow.python.util import deprecation 26from tensorflow.python.util import tf_inspect 27from tensorflow.python.util.tf_export import tf_export 28 29 30class InaccessibleTensorError(ValueError): 31 pass 32 33 34@tf_export("errors.OperatorNotAllowedInGraphError", v1=[]) 35class OperatorNotAllowedInGraphError(TypeError): 36 """An error is raised for unsupported operator in Graph execution. 37 38 For example, using a `tf.Tensor` as a Python `bool` in Graph execution 39 is not allowed. 40 """ 41 pass 42 43 44@tf_export("errors.OpError", v1=["errors.OpError", "OpError"]) 45@deprecation.deprecated_endpoints("OpError") 46class OpError(Exception): 47 """The base class for TensorFlow exceptions. 48 49 Usually, TensorFlow will raise a more specific subclass of `OpError` from the 50 `tf.errors` module. 51 """ 52 53 def __init__(self, node_def, op, message, error_code, *args): 54 """Creates a new `OpError` indicating that a particular op failed. 55 56 Args: 57 node_def: The `node_def_pb2.NodeDef` proto representing the op that 58 failed, if known; otherwise None. 59 op: The `ops.Operation` that failed, if known; otherwise None. During 60 eager execution, this field is always `None`. 61 message: The message string describing the failure. 62 error_code: The `error_codes_pb2.Code` describing the error. 63 *args: If not empty, it should contain a dictionary describing details 64 about the error. This argument is inspired by Abseil payloads: 65 https://github.com/abseil/abseil-cpp/blob/master/absl/status/status.h 66 """ 67 super(OpError, self).__init__() 68 self._node_def = node_def 69 self._op = op 70 self._message = message 71 self._error_code = error_code 72 if args: 73 self._experimental_payloads = args[0] 74 else: 75 self._experimental_payloads = {} 76 77 def __reduce__(self): 78 # Allow the subclasses to accept less arguments in their __init__. 79 init_argspec = tf_inspect.getargspec(self.__class__.__init__) 80 args = tuple(getattr(self, arg) for arg in init_argspec.args[1:]) 81 return self.__class__, args 82 83 @property 84 def message(self): 85 """The error message that describes the error.""" 86 return self._message 87 88 @property 89 def op(self): 90 """The operation that failed, if known. 91 92 *N.B.* If the failed op was synthesized at runtime, e.g. a `Send` 93 or `Recv` op, there will be no corresponding 94 `tf.Operation` 95 object. In that case, this will return `None`, and you should 96 instead use the `tf.errors.OpError.node_def` to 97 discover information about the op. 98 99 Returns: 100 The `Operation` that failed, or None. 101 """ 102 return self._op 103 104 @property 105 def error_code(self): 106 """The integer error code that describes the error.""" 107 return self._error_code 108 109 @property 110 def node_def(self): 111 """The `NodeDef` proto representing the op that failed.""" 112 return self._node_def 113 114 @property 115 def experimental_payloads(self): 116 """A dictionary describing the details of the error.""" 117 return self._experimental_payloads 118 119 def __str__(self): 120 if self._op is not None: 121 output = [ 122 "%s\n\nOriginal stack trace for %r:\n" % ( 123 self.message, 124 self._op.name, 125 ) 126 ] 127 curr_traceback_list = traceback.format_list(self._op.traceback or []) 128 output.extend(curr_traceback_list) 129 # pylint: disable=protected-access 130 original_op = self._op._original_op 131 # pylint: enable=protected-access 132 while original_op is not None: 133 output.append( 134 "\n...which was originally created as op %r, defined at:\n" % 135 (original_op.name,)) 136 prev_traceback_list = curr_traceback_list 137 curr_traceback_list = traceback.format_list(original_op.traceback or []) 138 139 # Attempt to elide large common subsequences of the subsequent 140 # stack traces. 141 # 142 # TODO(mrry): Consider computing the actual longest common subsequence. 143 is_eliding = False 144 elide_count = 0 145 last_elided_line = None 146 for line, line_in_prev in zip(curr_traceback_list, prev_traceback_list): 147 if line == line_in_prev: 148 if is_eliding: 149 elide_count += 1 150 last_elided_line = line 151 else: 152 output.append(line) 153 is_eliding = True 154 elide_count = 0 155 else: 156 if is_eliding: 157 if elide_count > 0: 158 output.extend([ 159 "[elided %d identical lines from previous traceback]\n" % 160 (elide_count - 1,), last_elided_line 161 ]) 162 is_eliding = False 163 output.extend(line) 164 165 # pylint: disable=protected-access 166 original_op = original_op._original_op 167 # pylint: enable=protected-access 168 return "".join(output) 169 else: 170 return self.message 171 172 173OK = error_codes_pb2.OK 174tf_export("errors.OK").export_constant(__name__, "OK") 175CANCELLED = error_codes_pb2.CANCELLED 176tf_export("errors.CANCELLED").export_constant(__name__, "CANCELLED") 177UNKNOWN = error_codes_pb2.UNKNOWN 178tf_export("errors.UNKNOWN").export_constant(__name__, "UNKNOWN") 179INVALID_ARGUMENT = error_codes_pb2.INVALID_ARGUMENT 180tf_export("errors.INVALID_ARGUMENT").export_constant(__name__, 181 "INVALID_ARGUMENT") 182DEADLINE_EXCEEDED = error_codes_pb2.DEADLINE_EXCEEDED 183tf_export("errors.DEADLINE_EXCEEDED").export_constant(__name__, 184 "DEADLINE_EXCEEDED") 185NOT_FOUND = error_codes_pb2.NOT_FOUND 186tf_export("errors.NOT_FOUND").export_constant(__name__, "NOT_FOUND") 187ALREADY_EXISTS = error_codes_pb2.ALREADY_EXISTS 188tf_export("errors.ALREADY_EXISTS").export_constant(__name__, "ALREADY_EXISTS") 189PERMISSION_DENIED = error_codes_pb2.PERMISSION_DENIED 190tf_export("errors.PERMISSION_DENIED").export_constant(__name__, 191 "PERMISSION_DENIED") 192UNAUTHENTICATED = error_codes_pb2.UNAUTHENTICATED 193tf_export("errors.UNAUTHENTICATED").export_constant(__name__, "UNAUTHENTICATED") 194RESOURCE_EXHAUSTED = error_codes_pb2.RESOURCE_EXHAUSTED 195tf_export("errors.RESOURCE_EXHAUSTED").export_constant(__name__, 196 "RESOURCE_EXHAUSTED") 197FAILED_PRECONDITION = error_codes_pb2.FAILED_PRECONDITION 198tf_export("errors.FAILED_PRECONDITION").export_constant(__name__, 199 "FAILED_PRECONDITION") 200ABORTED = error_codes_pb2.ABORTED 201tf_export("errors.ABORTED").export_constant(__name__, "ABORTED") 202OUT_OF_RANGE = error_codes_pb2.OUT_OF_RANGE 203tf_export("errors.OUT_OF_RANGE").export_constant(__name__, "OUT_OF_RANGE") 204UNIMPLEMENTED = error_codes_pb2.UNIMPLEMENTED 205tf_export("errors.UNIMPLEMENTED").export_constant(__name__, "UNIMPLEMENTED") 206INTERNAL = error_codes_pb2.INTERNAL 207tf_export("errors.INTERNAL").export_constant(__name__, "INTERNAL") 208UNAVAILABLE = error_codes_pb2.UNAVAILABLE 209tf_export("errors.UNAVAILABLE").export_constant(__name__, "UNAVAILABLE") 210DATA_LOSS = error_codes_pb2.DATA_LOSS 211tf_export("errors.DATA_LOSS").export_constant(__name__, "DATA_LOSS") 212 213 214# pylint: disable=line-too-long 215@tf_export("errors.CancelledError") 216class CancelledError(OpError): 217 """Raised when an operation or step is cancelled. 218 219 For example, a long-running operation (e.g. 220 `tf.QueueBase.enqueue` may be 221 cancelled by running another operation (e.g. 222 `tf.QueueBase.close`, 223 or by `tf.Session.close`. 224 A step that is running such a long-running operation will fail by raising 225 `CancelledError`. 226 227 @@__init__ 228 """ 229 230 def __init__(self, node_def, op, message, *args): 231 """Creates a `CancelledError`.""" 232 super(CancelledError, self).__init__(node_def, op, message, CANCELLED, 233 *args) 234 235 236# pylint: enable=line-too-long 237 238 239@tf_export("errors.UnknownError") 240class UnknownError(OpError): 241 """Unknown error. 242 243 An example of where this error may be returned is if a Status value 244 received from another address space belongs to an error-space that 245 is not known to this address space. Also, errors raised by APIs that 246 do not return enough error information may be converted to this 247 error. 248 249 @@__init__ 250 """ 251 252 def __init__(self, node_def, op, message, *args): 253 """Creates an `UnknownError`.""" 254 super(UnknownError, self).__init__(node_def, op, message, UNKNOWN, *args) 255 256 257@tf_export("errors.InvalidArgumentError") 258class InvalidArgumentError(OpError): 259 """Raised when an operation receives an invalid argument. 260 261 This error is typically raised when an op receives mismatched arguments. 262 263 Example: 264 265 >>> tf.reshape([1, 2, 3], (2,)) 266 Traceback (most recent call last): 267 ... 268 InvalidArgumentError: ... 269 270 @@__init__ 271 """ 272 273 def __init__(self, node_def, op, message, *args): 274 """Creates an `InvalidArgumentError`.""" 275 super(InvalidArgumentError, self).__init__(node_def, op, message, 276 INVALID_ARGUMENT, *args) 277 278 279@tf_export("errors.DeadlineExceededError") 280class DeadlineExceededError(OpError): 281 """Raised when a deadline expires before an operation could complete. 282 283 This exception is not currently used. 284 285 @@__init__ 286 """ 287 288 def __init__(self, node_def, op, message, *args): 289 """Creates a `DeadlineExceededError`.""" 290 super(DeadlineExceededError, self).__init__(node_def, op, message, 291 DEADLINE_EXCEEDED, *args) 292 293 294@tf_export("errors.NotFoundError") 295class NotFoundError(OpError): 296 """Raised when a requested entity (e.g., a file or directory) was not found. 297 298 For example, running the 299 `tf.WholeFileReader.read` 300 operation could raise `NotFoundError` if it receives the name of a file that 301 does not exist. 302 303 @@__init__ 304 """ 305 306 def __init__(self, node_def, op, message, *args): 307 """Creates a `NotFoundError`.""" 308 super(NotFoundError, self).__init__(node_def, op, message, NOT_FOUND, *args) 309 310 311@tf_export("errors.AlreadyExistsError") 312class AlreadyExistsError(OpError): 313 """Raised when an entity that we attempted to create already exists. 314 315 For example, running an operation that saves a file 316 (e.g. `tf.train.Saver.save`) 317 could potentially raise this exception if an explicit filename for an 318 existing file was passed. 319 320 @@__init__ 321 """ 322 323 def __init__(self, node_def, op, message, *args): 324 """Creates an `AlreadyExistsError`.""" 325 super(AlreadyExistsError, self).__init__(node_def, op, message, 326 ALREADY_EXISTS, *args) 327 328 329@tf_export("errors.PermissionDeniedError") 330class PermissionDeniedError(OpError): 331 """Raised when the caller does not have permission to run an operation. 332 333 For example, running the 334 `tf.WholeFileReader.read` 335 operation could raise `PermissionDeniedError` if it receives the name of a 336 file for which the user does not have the read file permission. 337 338 @@__init__ 339 """ 340 341 def __init__(self, node_def, op, message, *args): 342 """Creates a `PermissionDeniedError`.""" 343 super(PermissionDeniedError, self).__init__(node_def, op, message, 344 PERMISSION_DENIED, *args) 345 346 347@tf_export("errors.UnauthenticatedError") 348class UnauthenticatedError(OpError): 349 """The request does not have valid authentication credentials. 350 351 This exception is not currently used. 352 353 @@__init__ 354 """ 355 356 def __init__(self, node_def, op, message, *args): 357 """Creates an `UnauthenticatedError`.""" 358 super(UnauthenticatedError, self).__init__(node_def, op, message, 359 UNAUTHENTICATED, *args) 360 361 362@tf_export("errors.ResourceExhaustedError") 363class ResourceExhaustedError(OpError): 364 """Some resource has been exhausted. 365 366 For example, this error might be raised if a per-user quota is 367 exhausted, or perhaps the entire file system is out of space. 368 369 @@__init__ 370 """ 371 372 def __init__(self, node_def, op, message, *args): 373 """Creates a `ResourceExhaustedError`.""" 374 super(ResourceExhaustedError, self).__init__(node_def, op, message, 375 RESOURCE_EXHAUSTED, *args) 376 377 378@tf_export("errors.FailedPreconditionError") 379class FailedPreconditionError(OpError): 380 """Operation was rejected because the system is not in a state to execute it. 381 382 This exception is most commonly raised when running an operation 383 that reads a `tf.Variable` 384 before it has been initialized. 385 386 @@__init__ 387 """ 388 389 def __init__(self, node_def, op, message, *args): 390 """Creates a `FailedPreconditionError`.""" 391 super(FailedPreconditionError, self).__init__(node_def, op, message, 392 FAILED_PRECONDITION, *args) 393 394 395@tf_export("errors.AbortedError") 396class AbortedError(OpError): 397 """The operation was aborted, typically due to a concurrent action. 398 399 For example, running a 400 `tf.QueueBase.enqueue` 401 operation may raise `AbortedError` if a 402 `tf.QueueBase.close` operation 403 previously ran. 404 405 @@__init__ 406 """ 407 408 def __init__(self, node_def, op, message, *args): 409 """Creates an `AbortedError`.""" 410 super(AbortedError, self).__init__(node_def, op, message, ABORTED, *args) 411 412 413@tf_export("errors.OutOfRangeError") 414class OutOfRangeError(OpError): 415 """Raised when an operation iterates past the valid input range. 416 417 This exception is raised in "end-of-file" conditions, such as when a 418 `tf.QueueBase.dequeue` 419 operation is blocked on an empty queue, and a 420 `tf.QueueBase.close` 421 operation executes. 422 423 @@__init__ 424 """ 425 426 def __init__(self, node_def, op, message, *args): 427 """Creates an `OutOfRangeError`.""" 428 super(OutOfRangeError, self).__init__(node_def, op, message, OUT_OF_RANGE, 429 *args) 430 431 432@tf_export("errors.UnimplementedError") 433class UnimplementedError(OpError): 434 """Raised when an operation has not been implemented. 435 436 Some operations may raise this error when passed otherwise-valid 437 arguments that it does not currently support. For example, running 438 the `tf.nn.max_pool2d` operation 439 would raise this error if pooling was requested on the batch dimension, 440 because this is not yet supported. 441 442 @@__init__ 443 """ 444 445 def __init__(self, node_def, op, message, *args): 446 """Creates an `UnimplementedError`.""" 447 super(UnimplementedError, self).__init__(node_def, op, message, 448 UNIMPLEMENTED, *args) 449 450 451@tf_export("errors.InternalError") 452class InternalError(OpError): 453 """Raised when the system experiences an internal error. 454 455 This exception is raised when some invariant expected by the runtime 456 has been broken. Catching this exception is not recommended. 457 458 @@__init__ 459 """ 460 461 def __init__(self, node_def, op, message, *args): 462 """Creates an `InternalError`.""" 463 super(InternalError, self).__init__(node_def, op, message, INTERNAL, *args) 464 465 466@tf_export("errors.UnavailableError") 467class UnavailableError(OpError): 468 """Raised when the runtime is currently unavailable. 469 470 This exception is not currently used. 471 472 @@__init__ 473 """ 474 475 def __init__(self, node_def, op, message, *args): 476 """Creates an `UnavailableError`.""" 477 super(UnavailableError, self).__init__(node_def, op, message, UNAVAILABLE, 478 *args) 479 480 481@tf_export("errors.DataLossError") 482class DataLossError(OpError): 483 """Raised when unrecoverable data loss or corruption is encountered. 484 485 For example, this may be raised by running a 486 `tf.WholeFileReader.read` 487 operation, if the file is truncated while it is being read. 488 489 @@__init__ 490 """ 491 492 def __init__(self, node_def, op, message, *args): 493 """Creates a `DataLossError`.""" 494 super(DataLossError, self).__init__(node_def, op, message, DATA_LOSS, *args) 495 496 497_CODE_TO_EXCEPTION_CLASS = { 498 CANCELLED: CancelledError, 499 UNKNOWN: UnknownError, 500 INVALID_ARGUMENT: InvalidArgumentError, 501 DEADLINE_EXCEEDED: DeadlineExceededError, 502 NOT_FOUND: NotFoundError, 503 ALREADY_EXISTS: AlreadyExistsError, 504 PERMISSION_DENIED: PermissionDeniedError, 505 UNAUTHENTICATED: UnauthenticatedError, 506 RESOURCE_EXHAUSTED: ResourceExhaustedError, 507 FAILED_PRECONDITION: FailedPreconditionError, 508 ABORTED: AbortedError, 509 OUT_OF_RANGE: OutOfRangeError, 510 UNIMPLEMENTED: UnimplementedError, 511 INTERNAL: InternalError, 512 UNAVAILABLE: UnavailableError, 513 DATA_LOSS: DataLossError, 514} 515 516_pywrap_py_exception_registry.PyExceptionRegistry_Init(_CODE_TO_EXCEPTION_CLASS) 517 518_EXCEPTION_CLASS_TO_CODE = { 519 class_: code for code, class_ in _CODE_TO_EXCEPTION_CLASS.items() 520} 521 522 523@tf_export(v1=["errors.exception_type_from_error_code"]) 524def exception_type_from_error_code(error_code): 525 return _CODE_TO_EXCEPTION_CLASS[error_code] 526 527 528@tf_export(v1=["errors.error_code_from_exception_type"]) 529def error_code_from_exception_type(cls): 530 try: 531 return _EXCEPTION_CLASS_TO_CODE[cls] 532 except KeyError: 533 warnings.warn("Unknown class exception") 534 return UnknownError(None, None, "Unknown class exception", None) 535 536 537def _make_specific_exception(node_def, op, message, error_code): 538 try: 539 exc_type = exception_type_from_error_code(error_code) 540 return exc_type(node_def, op, message) 541 except KeyError: 542 warnings.warn("Unknown error code: %d" % error_code) 543 return UnknownError(node_def, op, message, error_code) 544 545 546# Named like a function for backwards compatibility with the 547# @tf_contextlib.contextmanager version, which was switched to a class to avoid 548# some object creation overhead. 549# TODO(b/77295559): expand use of TF_Status* SWIG typemap and deprecate this. 550@tf_export(v1=["errors.raise_exception_on_not_ok_status"]) # pylint: disable=invalid-name 551class raise_exception_on_not_ok_status(object): 552 """Context manager to check for C API status.""" 553 554 def __enter__(self): 555 self.status = c_api_util.ScopedTFStatus() 556 return self.status.status 557 558 def __exit__(self, type_arg, value_arg, traceback_arg): 559 try: 560 if c_api.TF_GetCode(self.status.status) != 0: 561 raise _make_specific_exception( 562 None, None, compat.as_text(c_api.TF_Message(self.status.status)), 563 c_api.TF_GetCode(self.status.status)) 564 # Delete the underlying status object from memory otherwise it stays alive 565 # as there is a reference to status from this from the traceback due to 566 # raise. 567 finally: 568 del self.status 569 return False # False values do not suppress exceptions 570