Reference#

pw_status: Exception-free error propagation for embedded

Status codes#

enumerator OK = 0#

OK indicates that the operation completede successfully. It is typical to check for this value before proceeding on any given call across an API or RPC boundary. To check this value, use the ok() member function rather than inspecting the raw code.

C++

pw::OkStatus()

C

PW_STATUS_OK

Python / Java / TypeScript

Status.OK

Rust

Ok(val)

enumerator CANCELLED = 1#

CANCELLED indicates the operation was cancelled, typically by the caller.

C++

pw::Status::Cancelled()

C

PW_STATUS_CANCELLED

Python / Java / TypeScript

Status.CANCELLED

Rust

Error::Cancelled

enumerator UNKNOWN = 2#

UNKNOWN indicates an unknown error occurred. In general, more specific errors should be raised, if possible. Errors raised by APIs that do not return enough error information may be converted to this error.

C++

pw::Status::Unknown()

C

PW_STATUS_UNKNOWN

Python / Java / TypeScript

Status.UNKNOWN

Rust

Error::Unknown

enumerator INVALID_ARGUMENT = 3#

INVALID_ARGUMENT indicates the caller specified an invalid argument, such as a malformed filename. Note that use of such errors should be narrowly limited to indicate the invalid nature of the arguments themselves. Errors with validly formed arguments that may cause errors with the state of the receiving system should be denoted with FAILED_PRECONDITION instead.

C++

pw::Status::InvalidArgument()

C

PW_STATUS_INVALID_ARGUMENT

Python / Java / TypeScript

Status.INVALID_ARGUMENT

Rust

Error::InvalidArgument

enumerator DEADLINE_EXCEEDED = 4#

DEADLINE_EXCEEDED indicates a deadline expired before the operation could complete. For operations that may change state within a system, this error may be returned even if the operation has completed successfully. For example, a successful response from a server could have been delayed long enough for the deadline to expire.

C++

pw::Status::DeadlineExceeded()

C

PW_STATUS_DEADLINE_EXCEEDED

Python / Java / TypeScript

Status.DEADLINE_EXCEEDED

Rust

Error::DeadlineExceeded

enumerator NOT_FOUND = 5#

NOT_FOUND indicates some requested entity (such as a file or directory) was not found.

NOT_FOUND is useful if a request should be denied for an entire class of users, such as during a gradual feature rollout or undocumented allowlist. If a request should be denied for specific sets of users, such as through user-based access control, use PERMISSION_DENIED instead.

C++

pw::Status::NotFound()

C

PW_STATUS_NOT_FOUND

Python / Java / TypeScript

Status.NOT_FOUND

Rust

Error::NotFound

enumerator ALREADY_EXISTS = 6#

ALREADY_EXISTS indicates that the entity a caller attempted to create (such as a file or directory) is already present.

C++

pw::Status::AlreadyExists()

C

PW_STATUS_ALREADY_EXISTS

Python / Java / TypeScript

Status.ALREADY_EXISTS

Rust

Error::AlreadyExists

enumerator PERMISSION_DENIED = 7#

PERMISSION_DENIED indicates that the caller does not have permission to execute the specified operation. Note that this error is different than an error due to an unauthenticated user. This error code does not imply the request is valid or the requested entity exists or satisfies any other pre-conditions.

PERMISSION_DENIED must not be used for rejections caused by exhausting some resource. Instead, use RESOURCE_EXHAUSTED for those errors. PERMISSION_DENIED must not be used if the caller cannot be identified. Instead, use UNAUTHENTICATED for those errors.

C++

pw::Status::PermissionDenied()

C

PW_STATUS_PERMISSION_DENIED

Python / Java / TypeScript

Status.PERMISSION_DENIED

Rust

Error::PermissionDenied

enumerator RESOURCE_EXHAUSTED = 8#

RESOURCE_EXHAUSTED indicates some resource has been exhausted, perhaps a per-user quota, or perhaps the entire file system is out of space.

C++

pw::Status::ResourceExhausted()

C

PW_STATUS_RESOURCE_EXHAUSTED

Python / Java / TypeScript

Status.RESOURCE_EXHAUSTED

Rust

Error::ResourceExhausted

enumerator FAILED_PRECONDITION = 9#

FAILED_PRECONDITION indicates that the operation was rejected because the system is not in a state required for the operation’s execution. For example, a directory to be deleted may be non-empty, an rmdir operation is applied to a non-directory, etc.

Some guidelines that may help a service implementer in deciding between FAILED_PRECONDITION, ABORTED, and UNAVAILABLE:

  1. Use UNAVAILABLE if the client can retry just the failing call.

  2. Use ABORTED if the client should retry at a higher transaction level (such as when a client-specified test-and-set fails, indicating the client should restart a read-modify-write sequence).

  3. Use FAILED_PRECONDITION if the client should not retry until the system state has been explicitly fixed. For example, if a rmdir fails because the directory is non-empty, FAILED_PRECONDITION should be returned since the client should not retry unless the files are deleted from the directory.

C++

pw::Status::FailedPrecondition()

C

PW_STATUS_FAILED_PRECONDITION

Python / Java / TypeScript

Status.FAILED_PRECONDITION

Rust

Error::FailedPrecondition

enumerator ABORTED = 10#

ABORTED indicates the operation was aborted, typically due to a concurrency issue such as a sequencer check failure or a failed transaction.

See the guidelines above for deciding between FAILED_PRECONDITION, ABORTED, and UNAVAILABLE.

C++

pw::Status::Aborted()

C

PW_STATUS_ABORTED

Python / Java / TypeScript

Status.ABORTED

Rust

Error::Aborted

enumerator OUT_OF_RANGE = 11#

OUT_OF_RANGE indicates the operation was attempted past the valid range, such as seeking or reading past an end-of-file.

Unlike INVALID_ARGUMENT, this error indicates a problem that may be fixed if the system state changes. For example, a 32-bit file system will generate INVALID_ARGUMENT if asked to read at an offset that is not in the range [0,2^32-1], but it will generate OUT_OF_RANGE if asked to read from an offset past the current file size.

There is a fair bit of overlap between FAILED_PRECONDITION and OUT_OF_RANGE. Use OUT_OF_RANGE (the more specific error) when it applies so that callers who are iterating through a space can easily look for an OUT_OF_RANGE error to detect when they are done.

C++

pw::Status::OutOfRange()

C

PW_STATUS_OUT_OF_RANGE

Python / Java / TypeScript

Status.OUT_OF_RANGE

Rust

Error::OutOfRange

enumerator UNIMPLEMENTED = 12#

UNIMPLEMENTED indicates the operation is not implemented or supported in this service. In this case, the operation should not be re-attempted.

C++

pw::Status::Unimplemented()

C

PW_STATUS_UNIMPLEMENTED

Python / Java / TypeScript

Status.UNIMPLEMENTED

Rust

Error::Unimplemented

enumerator INTERNAL = 13#

INTERNAL indicates an internal error has occurred and some invariants expected by the underlying system have not been satisfied. This error code is reserved for serious errors.

C++

pw::Status::Internal()

C

PW_STATUS_INTERNAL

Python / Java / TypeScript

Status.INTERNAL

Rust

Error::Internal

enumerator UNAVAILABLE = 14#

UNAVAILABLE indicates the service is currently unavailable and that this is most likely a transient condition. An error such as this can be corrected by retrying with a backoff scheme. Note that it is not always safe to retry non-idempotent operations.

See the guidelines above for deciding between FAILED_PRECONDITION, ABORTED, and UNAVAILABLE.

C++

pw::Status::Unavailable()

C

PW_STATUS_UNAVAILABLE

Python / Java / TypeScript

Status.UNAVAILABLE

Rust

Error::Unavailable

enumerator DATA_LOSS = 15#

DATA_LOSS indicates that unrecoverable data loss or corruption has occurred. As this error is serious, proper alerting should be attached to errors such as this.

C++

pw::Status::DataLoss()

C

PW_STATUS_DATA_LOSS

Python / Java / TypeScript

Status.DATA_LOSS

Rust

Error::DataLoss

enumerator UNAUTHENTICATED = 16#

UNAUTHENTICATED indicates that the request does not have valid authentication credentials for the operation. Correct the authentication and try again.

C++

pw::Status::Unauthenticated()

C

PW_STATUS_UNAUTHENTICATED

Python / Java / TypeScript

Status.UNAUTHENTICATED

Rust

Error::Unauthenticated

C++ API#

class Status#

Status is a thin, zero-cost abstraction around the pw_Status enum. It initializes to OK by default and adds ok() and str() methods. Implicit conversions are permitted between pw_Status and pw::Status.

An OK Status is created by the pw::OkStatus() function or by the default Status constructor. Non-OK Status is created with a static member function that corresponds with the status code.

Public Functions

inline constexpr Code code() const#

Returns the Status::Code (pw_Status) for this Status.

inline constexpr bool ok() const#

True if the status is OK .

This function is provided in place of an IsOk() function.

inline constexpr void Update(Status other)#

Updates this Status to the provided Status IF this status is OK . This is useful for tracking the first encountered error, as calls to this helper will not change one error status to another error status.

inline constexpr void IgnoreError() const#

Ignores any errors. This method does nothing except potentially suppress complaints from any tools that are checking that errors are not dropped on the floor.

inline const char *str() const#

Returns a null-terminated string representation of the Status.

constexpr Status pw::OkStatus()#

Returns an OK status. Equivalent to Status() or Status(PW_STATUS_OK). This function is used instead of a Status::Ok() function, which would be too similar to Status::ok().

enum pw_Status#

Enum to use in place of pw::Status in C code. Always use pw::Status in C++ code.

The values of the pw_Status enum are all-caps and prefixed with PW_STATUS_. For example, PW_STATUS_DATA_LOSS corresponds with DATA_LOSS.

class StatusWithSize#

StatusWithSize stores a status and an unsigned integer. The integer must not exceed StatusWithSize::max_size(), which is 134,217,727 (2**27 - 1) on 32-bit systems.

StatusWithSize is useful for reporting the number of bytes read or written in an operation along with the status. For example, a function that writes a formatted string may want to report both the number of characters written and whether it ran out of space.

StatusWithSize is more efficient than its alternatives. It packs a status and size into a single word, which can be returned from a function in a register. Because they are packed together, the size is limited to max_size().

StatusWithSize’s alternatives result in larger code size. For example:

  1. Return status, pass size output as a pointer argument.

    Requires an additional argument and forces the output argument to the stack in order to pass an address, increasing code size.

  2. Return an object with Status and size members.

    At least for ARMv7-M, the returned struct is created on the stack, which increases code size.

Public Functions

inline explicit constexpr StatusWithSize()#

Creates a StatusWithSize with status OK and a size of 0.

template<typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
inline explicit constexpr StatusWithSize(T size)#

Creates a StatusWithSize with status OK and the provided size. std::enable_if is used to prevent enum types (e.g. Status::Code) from being used.

inline explicit constexpr StatusWithSize(Status status, size_t size)#

Creates a StatusWithSize with the provided status and size.

constexpr StatusWithSize(const StatusWithSize&) = default#
constexpr StatusWithSize &operator=(const StatusWithSize&) = default#
inline constexpr void UpdateAndAdd(StatusWithSize new_status_with_size)#

Update s this status and adds to size.

The resulting StatusWithSize will have a size of this->size() + new_status_with_size.size()

The resulting status will be OK if both statuses are OK, otherwise it will take on the earliest non-OK status.

inline constexpr void ZeroIfNotOk()#

Zeroes the size if the status is not OK.

inline constexpr size_t size() const#

Returns the size. The size is always present, even if status() is an error.

inline constexpr bool ok() const#

True if status() == OkStatus().

inline constexpr void IgnoreError() const#

Ignores any errors. This method does nothing except potentially suppress complaints from any tools that are checking that errors are not dropped on the floor.

inline constexpr Status status() const#
inline constexpr bool IsCancelled() const#
inline constexpr bool IsUnknown() const#
inline constexpr bool IsInvalidArgument() const#
inline constexpr bool IsDeadlineExceeded() const#
inline constexpr bool IsNotFound() const#
inline constexpr bool IsAlreadyExists() const#
inline constexpr bool IsPermissionDenied() const#
inline constexpr bool IsResourceExhausted() const#
inline constexpr bool IsFailedPrecondition() const#
inline constexpr bool IsAborted() const#
inline constexpr bool IsOutOfRange() const#
inline constexpr bool IsUnimplemented() const#
inline constexpr bool IsInternal() const#
inline constexpr bool IsUnavailable() const#
inline constexpr bool IsDataLoss() const#
inline constexpr bool IsUnauthenticated() const#

Public Static Functions

static inline constexpr StatusWithSize Cancelled(size_t size = 0)#
static inline constexpr StatusWithSize Unknown(size_t size = 0)#
static inline constexpr StatusWithSize InvalidArgument(size_t size = 0)#
static inline constexpr StatusWithSize DeadlineExceeded(size_t size = 0)#
static inline constexpr StatusWithSize NotFound(size_t size = 0)#
static inline constexpr StatusWithSize AlreadyExists(size_t size = 0)#
static inline constexpr StatusWithSize PermissionDenied(size_t size = 0)#
static inline constexpr StatusWithSize Unauthenticated(size_t size = 0)#
static inline constexpr StatusWithSize ResourceExhausted(size_t size = 0)#
static inline constexpr StatusWithSize FailedPrecondition(size_t size = 0)#
static inline constexpr StatusWithSize Aborted(size_t size = 0)#
static inline constexpr StatusWithSize OutOfRange(size_t size = 0)#
static inline constexpr StatusWithSize Unimplemented(size_t size = 0)#
static inline constexpr StatusWithSize Internal(size_t size = 0)#
static inline constexpr StatusWithSize Unavailable(size_t size = 0)#
static inline constexpr StatusWithSize DataLoss(size_t size = 0)#
static inline constexpr size_t max_size()#

The maximum valid value for size.

PW_TRY(expr)#

Returns early if expr is a non-OK Status or Result.

PW_TRY_ASSIGN(lhs, expression)#

Returns early if expression is a non-OK Result. If expression is okay, assigns the inner value to lhs.

PW_TRY_WITH_SIZE(expr)#

Returns early if expr is a non-OK Status or StatusWithSize.

This is designed for use in functions that return a StatusWithSize.

PW_CO_TRY(expr)#

Like PW_TRY, but using co_return instead of early return.

This is necessary because only co_return can be used inside of a coroutine, and there is no way to detect whether particular code is running within a coroutine or not.

PW_CO_TRY_ASSIGN(lhs, expression)#

Like PW_TRY_ASSIGN, but using co_return instead of early return.

This is necessary because only co_return can be used inside of a coroutine, and there is no way to detect whether particular code is running within a coroutine or not.

Unused result warnings#

If the PW_STATUS_CFG_CHECK_IF_USED option is enabled, pw::Status objects returned from function calls must be used or it is a compilation error. To silence these warnings call IgnoreError() on the returned status object.

PW_STATUS_CFG_CHECK_IF_USED defaults to false in GN and CMake, but true in Bazel. Pigweed compiles with this option enabled, but projects that use Pigweed will need to be updated to compile with this option. After all projects have migrated, unused result warnings will be enabled unconditionally.

C API#

pw_status provides the C-compatible pw_Status enum for the status codes. For ease of use, pw::Status implicitly converts to and from pw_Status. However, the pw_Status enum should never be used in C++; instead use the pw::Status class.

Rust API#

pw_status’s Rust API is documented in our rustdoc API docs.