• 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 
16 #ifndef TENSORFLOW_CORE_PLATFORM_ERRORS_H_
17 #define TENSORFLOW_CORE_PLATFORM_ERRORS_H_
18 
19 #include <sstream>
20 #include <string>
21 #include <utility>
22 
23 #include "absl/base/attributes.h"
24 #include "absl/strings/str_join.h"
25 #include "tensorflow/core/platform/logging.h"
26 #include "tensorflow/core/platform/macros.h"
27 #include "tensorflow/core/platform/status.h"
28 #include "tensorflow/core/platform/str_util.h"
29 #include "tensorflow/core/platform/strcat.h"
30 
31 namespace tensorflow {
32 namespace errors {
33 
34 namespace internal {
35 
36 // The DECLARE_ERROR macro below only supports types that can be converted
37 // into StrCat's AlphaNum. For the other types we rely on a slower path
38 // through std::stringstream. To add support of a new type, it is enough to
39 // make sure there is an operator<<() for it:
40 //
41 //   std::ostream& operator<<(std::ostream& os, const MyType& foo) {
42 //     os << foo.ToString();
43 //     return os;
44 //   }
45 // Eventually absl::strings will have native support for this and we will be
46 // able to completely remove PrepareForStrCat().
47 template <typename T>
48 typename std::enable_if<!std::is_convertible<T, strings::AlphaNum>::value,
49                         std::string>::type
PrepareForStrCat(const T & t)50 PrepareForStrCat(const T& t) {
51   std::stringstream ss;
52   ss << t;
53   return ss.str();
54 }
PrepareForStrCat(const strings::AlphaNum & a)55 inline const strings::AlphaNum& PrepareForStrCat(const strings::AlphaNum& a) {
56   return a;
57 }
58 
59 }  // namespace internal
60 
61 // Maps UNIX errors into a Status.
62 Status IOError(const string& context, int err_number);
63 
64 // Returns all payloads from a Status as a key-value map.
GetPayloads(const::tensorflow::Status & status)65 inline std::unordered_map<std::string, std::string> GetPayloads(
66     const ::tensorflow::Status& status) {
67   std::unordered_map<std::string, std::string> payloads;
68   status.ForEachPayload(
69       [&payloads](tensorflow::StringPiece key, tensorflow::StringPiece value) {
70         payloads[std::string(key)] = std::string(value);
71       });
72   return payloads;
73 }
74 
75 // Inserts all given payloads into the given status. Will overwrite existing
76 // payloads if they exist with the same key.
InsertPayloads(::tensorflow::Status & status,const std::unordered_map<std::string,std::string> & payloads)77 inline void InsertPayloads(
78     ::tensorflow::Status& status,
79     const std::unordered_map<std::string, std::string>& payloads) {
80   for (const auto& payload : payloads) {
81     status.SetPayload(payload.first, payload.second);
82   }
83 }
84 
85 // Copies all payloads from one Status to another. Will overwrite existing
86 // payloads in the destination if they exist with the same key.
CopyPayloads(const::tensorflow::Status & from,::tensorflow::Status & to)87 inline void CopyPayloads(const ::tensorflow::Status& from,
88                          ::tensorflow::Status& to) {
89   from.ForEachPayload(
90       [&to](tensorflow::StringPiece key, tensorflow::StringPiece value) {
91         to.SetPayload(key, value);
92       });
93 }
94 
95 // Creates a new status with the given code, message and payloads.
Create(Code code,::tensorflow::StringPiece message,const std::unordered_map<std::string,std::string> & payloads)96 inline ::tensorflow::Status Create(
97     Code code, ::tensorflow::StringPiece message,
98     const std::unordered_map<std::string, std::string>& payloads) {
99   Status status(code, message);
100   InsertPayloads(status, payloads);
101   return status;
102 }
103 
104 // Returns a new Status, replacing its message with the given.
CreateWithUpdatedMessage(const::tensorflow::Status & status,::tensorflow::StringPiece message)105 inline ::tensorflow::Status CreateWithUpdatedMessage(
106     const ::tensorflow::Status& status, ::tensorflow::StringPiece message) {
107   return Create(status.code(), message, GetPayloads(status));
108 }
109 
110 // Append some context to an error message.  Each time we append
111 // context put it on a new line, since it is possible for there
112 // to be several layers of additional context.
113 template <typename... Args>
AppendToMessage(::tensorflow::Status * status,Args...args)114 void AppendToMessage(::tensorflow::Status* status, Args... args) {
115   auto new_status = ::tensorflow::Status(
116       status->code(),
117       ::tensorflow::strings::StrCat(status->error_message(), "\n\t", args...));
118   CopyPayloads(*status, new_status);
119   *status = std::move(new_status);
120 }
121 
122 // For propagating errors when calling a function.
123 #define TF_RETURN_IF_ERROR(...)                          \
124   do {                                                   \
125     ::tensorflow::Status _status = (__VA_ARGS__);        \
126     if (TF_PREDICT_FALSE(!_status.ok())) return _status; \
127   } while (0)
128 
129 #define TF_RETURN_WITH_CONTEXT_IF_ERROR(expr, ...)                  \
130   do {                                                              \
131     ::tensorflow::Status _status = (expr);                          \
132     if (TF_PREDICT_FALSE(!_status.ok())) {                          \
133       ::tensorflow::errors::AppendToMessage(&_status, __VA_ARGS__); \
134       return _status;                                               \
135     }                                                               \
136   } while (0)
137 
138 // Convenience functions for generating and using error status.
139 // Example usage:
140 //   status.Update(errors::InvalidArgument("The ", foo, " isn't right."));
141 //   if (errors::IsInvalidArgument(status)) { ... }
142 //   switch (status.code()) { case error::INVALID_ARGUMENT: ... }
143 
144 // Cancelled
145 template <typename... Args>
Cancelled(Args...args)146 ::tensorflow::Status Cancelled(Args... args) {
147   return ::tensorflow::Status(
148       ::tensorflow::error::Code::CANCELLED,
149       ::tensorflow::strings::StrCat(
150           ::tensorflow::errors::internal::PrepareForStrCat(args)...));
151 }
152 template <typename... Args>
CancelledWithPayloads(const::tensorflow::StringPiece & message,const std::unordered_map<std::string,std::string> & payloads)153 ::tensorflow::Status CancelledWithPayloads(
154     const ::tensorflow::StringPiece& message,
155     const std::unordered_map<std::string, std::string>& payloads) {
156   return errors::Create(::tensorflow::error::CANCELLED, message, payloads);
157 }
158 
159 // InvalidArgument
160 template <typename... Args>
InvalidArgument(Args...args)161 ::tensorflow::Status InvalidArgument(Args... args) {
162   return ::tensorflow::Status(
163       ::tensorflow::error::Code::INVALID_ARGUMENT,
164       ::tensorflow::strings::StrCat(
165           ::tensorflow::errors::internal::PrepareForStrCat(args)...));
166 }
167 template <typename... Args>
InvalidArgumentWithPayloads(const::tensorflow::StringPiece & message,const std::unordered_map<std::string,std::string> & payloads)168 ::tensorflow::Status InvalidArgumentWithPayloads(
169     const ::tensorflow::StringPiece& message,
170     const std::unordered_map<std::string, std::string>& payloads) {
171   return errors::Create(::tensorflow::error::INVALID_ARGUMENT, message,
172                         payloads);
173 }
174 
175 // NotFound
176 template <typename... Args>
NotFound(Args...args)177 ::tensorflow::Status NotFound(Args... args) {
178   return ::tensorflow::Status(
179       ::tensorflow::error::Code::NOT_FOUND,
180       ::tensorflow::strings::StrCat(
181           ::tensorflow::errors::internal::PrepareForStrCat(args)...));
182 }
183 template <typename... Args>
NotFoundWithPayloads(const::tensorflow::StringPiece & message,const std::unordered_map<std::string,std::string> & payloads)184 ::tensorflow::Status NotFoundWithPayloads(
185     const ::tensorflow::StringPiece& message,
186     const std::unordered_map<std::string, std::string>& payloads) {
187   return errors::Create(::tensorflow::error::NOT_FOUND, message, payloads);
188 }
189 
190 // AlreadyExists
191 template <typename... Args>
AlreadyExists(Args...args)192 ::tensorflow::Status AlreadyExists(Args... args) {
193   return ::tensorflow::Status(
194       ::tensorflow::error::Code::ALREADY_EXISTS,
195       ::tensorflow::strings::StrCat(
196           ::tensorflow::errors::internal::PrepareForStrCat(args)...));
197 }
198 template <typename... Args>
AlreadyExistsWithPayloads(const::tensorflow::StringPiece & message,const std::unordered_map<std::string,std::string> & payloads)199 ::tensorflow::Status AlreadyExistsWithPayloads(
200     const ::tensorflow::StringPiece& message,
201     const std::unordered_map<std::string, std::string>& payloads) {
202   return errors::Create(::tensorflow::error::ALREADY_EXISTS, message, payloads);
203 }
204 
205 // ResourceExhausted
206 template <typename... Args>
ResourceExhausted(Args...args)207 ::tensorflow::Status ResourceExhausted(Args... args) {
208   return ::tensorflow::Status(
209       ::tensorflow::error::Code::RESOURCE_EXHAUSTED,
210       ::tensorflow::strings::StrCat(
211           ::tensorflow::errors::internal::PrepareForStrCat(args)...));
212 }
213 template <typename... Args>
ResourceExhaustedWithPayloads(const::tensorflow::StringPiece & message,const std::unordered_map<std::string,std::string> & payloads)214 ::tensorflow::Status ResourceExhaustedWithPayloads(
215     const ::tensorflow::StringPiece& message,
216     const std::unordered_map<std::string, std::string>& payloads) {
217   return errors::Create(::tensorflow::error::RESOURCE_EXHAUSTED, message,
218                         payloads);
219 }
220 
221 // Unavailable
222 template <typename... Args>
Unavailable(Args...args)223 ::tensorflow::Status Unavailable(Args... args) {
224   return ::tensorflow::Status(
225       ::tensorflow::error::Code::UNAVAILABLE,
226       ::tensorflow::strings::StrCat(
227           ::tensorflow::errors::internal::PrepareForStrCat(args)...));
228 }
229 template <typename... Args>
UnavailableWithPayloads(const::tensorflow::StringPiece & message,const std::unordered_map<std::string,std::string> & payloads)230 ::tensorflow::Status UnavailableWithPayloads(
231     const ::tensorflow::StringPiece& message,
232     const std::unordered_map<std::string, std::string>& payloads) {
233   return errors::Create(::tensorflow::error::UNAVAILABLE, message, payloads);
234 }
235 
236 // FailedPrecondition
237 template <typename... Args>
FailedPrecondition(Args...args)238 ::tensorflow::Status FailedPrecondition(Args... args) {
239   return ::tensorflow::Status(
240       ::tensorflow::error::Code::FAILED_PRECONDITION,
241       ::tensorflow::strings::StrCat(
242           ::tensorflow::errors::internal::PrepareForStrCat(args)...));
243 }
244 template <typename... Args>
FailedPreconditionWithPayloads(const::tensorflow::StringPiece & message,const std::unordered_map<std::string,std::string> & payloads)245 ::tensorflow::Status FailedPreconditionWithPayloads(
246     const ::tensorflow::StringPiece& message,
247     const std::unordered_map<std::string, std::string>& payloads) {
248   return errors::Create(::tensorflow::error::FAILED_PRECONDITION, message,
249                         payloads);
250 }
251 
252 // OutOfRange
253 template <typename... Args>
OutOfRange(Args...args)254 ::tensorflow::Status OutOfRange(Args... args) {
255   return ::tensorflow::Status(
256       ::tensorflow::error::Code::OUT_OF_RANGE,
257       ::tensorflow::strings::StrCat(
258           ::tensorflow::errors::internal::PrepareForStrCat(args)...));
259 }
260 template <typename... Args>
OutOfRangeWithPayloads(const::tensorflow::StringPiece & message,const std::unordered_map<std::string,std::string> & payloads)261 ::tensorflow::Status OutOfRangeWithPayloads(
262     const ::tensorflow::StringPiece& message,
263     const std::unordered_map<std::string, std::string>& payloads) {
264   return errors::Create(::tensorflow::error::OUT_OF_RANGE, message, payloads);
265 }
266 
267 // Unimplemented
268 template <typename... Args>
Unimplemented(Args...args)269 ::tensorflow::Status Unimplemented(Args... args) {
270   return ::tensorflow::Status(
271       ::tensorflow::error::Code::UNIMPLEMENTED,
272       ::tensorflow::strings::StrCat(
273           ::tensorflow::errors::internal::PrepareForStrCat(args)...));
274 }
275 template <typename... Args>
UnimplementedWithPayloads(const::tensorflow::StringPiece & message,const std::unordered_map<std::string,std::string> & payloads)276 ::tensorflow::Status UnimplementedWithPayloads(
277     const ::tensorflow::StringPiece& message,
278     const std::unordered_map<std::string, std::string>& payloads) {
279   return errors::Create(::tensorflow::error::UNIMPLEMENTED, message, payloads);
280 }
281 
282 // Internal
283 template <typename... Args>
Internal(Args...args)284 ::tensorflow::Status Internal(Args... args) {
285   return ::tensorflow::Status(
286       ::tensorflow::error::Code::INTERNAL,
287       ::tensorflow::strings::StrCat(
288           ::tensorflow::errors::internal::PrepareForStrCat(args)...));
289 }
290 template <typename... Args>
InternalWithPayloads(const::tensorflow::StringPiece & message,const std::unordered_map<std::string,std::string> & payloads)291 ::tensorflow::Status InternalWithPayloads(
292     const ::tensorflow::StringPiece& message,
293     const std::unordered_map<std::string, std::string>& payloads) {
294   return errors::Create(::tensorflow::error::INTERNAL, message, payloads);
295 }
296 
297 // Aborted
298 template <typename... Args>
Aborted(Args...args)299 ::tensorflow::Status Aborted(Args... args) {
300   return ::tensorflow::Status(
301       ::tensorflow::error::Code::ABORTED,
302       ::tensorflow::strings::StrCat(
303           ::tensorflow::errors::internal::PrepareForStrCat(args)...));
304 }
305 template <typename... Args>
AbortedWithPayloads(const::tensorflow::StringPiece & message,const std::unordered_map<std::string,std::string> & payloads)306 ::tensorflow::Status AbortedWithPayloads(
307     const ::tensorflow::StringPiece& message,
308     const std::unordered_map<std::string, std::string>& payloads) {
309   return errors::Create(::tensorflow::error::ABORTED, message, payloads);
310 }
311 
312 // DeadlineExceeded
313 template <typename... Args>
DeadlineExceeded(Args...args)314 ::tensorflow::Status DeadlineExceeded(Args... args) {
315   return ::tensorflow::Status(
316       ::tensorflow::error::Code::DEADLINE_EXCEEDED,
317       ::tensorflow::strings::StrCat(
318           ::tensorflow::errors::internal::PrepareForStrCat(args)...));
319 }
320 template <typename... Args>
DeadlineExceededWithPayloads(const::tensorflow::StringPiece & message,const std::unordered_map<std::string,std::string> & payloads)321 ::tensorflow::Status DeadlineExceededWithPayloads(
322     const ::tensorflow::StringPiece& message,
323     const std::unordered_map<std::string, std::string>& payloads) {
324   return errors::Create(::tensorflow::error::DEADLINE_EXCEEDED, message,
325                         payloads);
326 }
327 
328 // DataLoss
329 template <typename... Args>
DataLoss(Args...args)330 ::tensorflow::Status DataLoss(Args... args) {
331   return ::tensorflow::Status(
332       ::tensorflow::error::Code::DATA_LOSS,
333       ::tensorflow::strings::StrCat(
334           ::tensorflow::errors::internal::PrepareForStrCat(args)...));
335 }
336 template <typename... Args>
DataLossWithPayloads(const::tensorflow::StringPiece & message,const std::unordered_map<std::string,std::string> & payloads)337 ::tensorflow::Status DataLossWithPayloads(
338     const ::tensorflow::StringPiece& message,
339     const std::unordered_map<std::string, std::string>& payloads) {
340   return errors::Create(::tensorflow::error::DATA_LOSS, message, payloads);
341 }
342 
343 // Unknown
344 template <typename... Args>
Unknown(Args...args)345 ::tensorflow::Status Unknown(Args... args) {
346   return ::tensorflow::Status(
347       ::tensorflow::error::Code::UNKNOWN,
348       ::tensorflow::strings::StrCat(
349           ::tensorflow::errors::internal::PrepareForStrCat(args)...));
350 }
351 template <typename... Args>
UnknownPayloads(const::tensorflow::StringPiece & message,const std::unordered_map<std::string,std::string> & payloads)352 ::tensorflow::Status UnknownPayloads(
353     const ::tensorflow::StringPiece& message,
354     const std::unordered_map<std::string, std::string>& payloads) {
355   return errors::Create(::tensorflow::error::UNKNOWN, message, payloads);
356 }
357 // PermissionDenied
358 template <typename... Args>
PermissionDenied(Args...args)359 ::tensorflow::Status PermissionDenied(Args... args) {
360   return ::tensorflow::Status(
361       ::tensorflow::error::Code::PERMISSION_DENIED,
362       ::tensorflow::strings::StrCat(
363           ::tensorflow::errors::internal::PrepareForStrCat(args)...));
364 }
365 template <typename... Args>
PermissionDeniedWithPayloads(const::tensorflow::StringPiece & message,const std::unordered_map<std::string,std::string> & payloads)366 ::tensorflow::Status PermissionDeniedWithPayloads(
367     const ::tensorflow::StringPiece& message,
368     const std::unordered_map<std::string, std::string>& payloads) {
369   return errors::Create(::tensorflow::error::PERMISSION_DENIED, message,
370                         payloads);
371 }
372 
373 // Unauthenticated
374 template <typename... Args>
Unauthenticated(Args...args)375 ::tensorflow::Status Unauthenticated(Args... args) {
376   return ::tensorflow::Status(
377       ::tensorflow::error::Code::UNAUTHENTICATED,
378       ::tensorflow::strings::StrCat(
379           ::tensorflow::errors::internal::PrepareForStrCat(args)...));
380 }
381 template <typename... Args>
UnauthenticatedWithPayloads(const::tensorflow::StringPiece & message,const std::unordered_map<std::string,std::string> & payloads)382 ::tensorflow::Status UnauthenticatedWithPayloads(
383     const ::tensorflow::StringPiece& message,
384     const std::unordered_map<std::string, std::string>& payloads) {
385   return errors::Create(::tensorflow::error::UNAUTHENTICATED, message,
386                         payloads);
387 }
388 
389 bool IsAborted(const Status& status);
390 bool IsAlreadyExists(const Status& status);
391 bool IsCancelled(const Status& status);
392 bool IsDataLoss(const Status& status);
393 bool IsDeadlineExceeded(const Status& status);
394 bool IsFailedPrecondition(const Status& status);
395 bool IsInternal(const Status& status);
396 bool IsInvalidArgument(const Status& status);
397 bool IsNotFound(const Status& status);
398 bool IsOutOfRange(const Status& status);
399 bool IsPermissionDenied(const Status& status);
400 bool IsResourceExhausted(const Status& status);
401 bool IsUnauthenticated(const Status& status);
402 bool IsUnavailable(const Status& status);
403 bool IsUnimplemented(const Status& status);
404 bool IsUnknown(const Status& status);
405 
406 // Produces a formatted string pattern from the name which can uniquely identify
407 // this node upstream to produce an informative error message. The pattern
408 // followed is: {{node <name>}}
409 // Note: The pattern below determines the regex _NODEDEF_NAME_RE in the file
410 // tensorflow/python/client/session.py
411 // LINT.IfChange
FormatNodeNameForError(const std::string & name)412 inline std::string FormatNodeNameForError(const std::string& name) {
413   return strings::StrCat("{{node ", name, "}}");
414 }
415 // LINT.ThenChange(//tensorflow/python/client/session.py)
416 template <typename T>
FormatNodeNamesForError(const T & names)417 std::string FormatNodeNamesForError(const T& names) {
418   return absl::StrJoin(
419       names, ", ", [](std::string* output, const std::string& s) {
420         ::tensorflow::strings::StrAppend(output, FormatNodeNameForError(s));
421       });
422 }
423 // LINT.IfChange
FormatColocationNodeForError(const std::string & name)424 inline std::string FormatColocationNodeForError(const std::string& name) {
425   return strings::StrCat("{{colocation_node ", name, "}}");
426 }
427 // LINT.ThenChange(//tensorflow/python/framework/error_interpolation.py)
428 template <typename T>
FormatColocationNodeForError(const T & names)429 std::string FormatColocationNodeForError(const T& names) {
430   return absl::StrJoin(names, ", ",
431                        [](std::string* output, const std::string& s) {
432                          ::tensorflow::strings::StrAppend(
433                              output, FormatColocationNodeForError(s));
434                        });
435 }
436 
FormatFunctionForError(const std::string & name)437 inline std::string FormatFunctionForError(const std::string& name) {
438   return strings::StrCat("{{function_node ", name, "}}");
439 }
440 
ReplaceErrorFromNonCommunicationOps(const Status s,const std::string & op_name)441 inline Status ReplaceErrorFromNonCommunicationOps(const Status s,
442                                                   const std::string& op_name) {
443   assert(::tensorflow::errors::IsUnavailable(s));
444   return Status(
445       error::INTERNAL,
446       strings::StrCat(
447           s.error_message(), "\nExecuting non-communication op <", op_name,
448           "> originally returned UnavailableError, and was replaced by "
449           "InternalError to avoid invoking TF network error handling logic."));
450 }
451 
452 template <typename T>
FormatOriginalNodeLocationForError(const T & node_names,const T & func_names)453 std::string FormatOriginalNodeLocationForError(const T& node_names,
454                                                const T& func_names) {
455   std::vector<std::string> error_message;
456   for (int i = 0; i != node_names.size(); ++i) {
457     if (i != 0) {
458       error_message.push_back(", ");
459     }
460     if (i < func_names.size()) {
461       error_message.push_back(FormatFunctionForError(func_names[i]));
462     }
463     error_message.push_back(FormatNodeNameForError(node_names[i]));
464   }
465   return absl::StrJoin(error_message, "");
466 }
467 
468 // The CanonicalCode() for non-errors.
469 using ::tensorflow::error::OK;
470 
471 }  // namespace errors
472 }  // namespace tensorflow
473 
474 #endif  // TENSORFLOW_CORE_PLATFORM_ERRORS_H_
475