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