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