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