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