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