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