• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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