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