Errors

Errors in CAF have a code and a category, similar to std::error_code and std::error_condition. Unlike its counterparts from the C++ standard library, error is platform-neutral and serializable.

Class Interface

Constructors

(Enum code)

Constructs an error with given error code.

(Enum code, message context)

Constructs an error with given error code and additional context.

Observers

uint8_t code()

Returns the error code as 8-bit integer.

type_id_t category()

Returns the type ID of the Enum type used to construct this error.

message context()

Returns additional context information

explicit operator bool()

Returns code() != 0

Add Custom Error Categories

Adding custom error categories requires these steps:

  • Declare an enum class of type uint8_t with error codes starting at 1. CAF always interprets the value 0 as no error.

  • Assign a type ID to your enum type.

  • Specialize caf::is_error_code_enum for your enum type. For this step, CAF offers the macro CAF_ERROR_CODE_ENUM to generate the boilerplate code necessary.

The following example illustrates all these steps for a custom error code enum called math_error.

enum class math_error : uint8_t {
  division_by_zero = 1,
};

std::string to_string(math_error x) {
  switch (x) {
    case math_error::division_by_zero:
      return "division_by_zero";
    default:
      return "-unknown-error-";
  }
}

bool from_string(std::string_view in, math_error& out) {
  if (in == "division_by_zero") {
    out = math_error::division_by_zero;
    return true;
  } else {
    return false;
  }
}

bool from_integer(uint8_t in, math_error& out) {
  if (in == 1) {
    out = math_error::division_by_zero;
    return true;
  } else {
    return false;
  }
}

template <class Inspector>
bool inspect(Inspector& f, math_error& x) {
  return caf::default_enum_inspect(f, x);
}

CAF_BEGIN_TYPE_ID_BLOCK(divider, first_custom_type_id)

  CAF_ADD_TYPE_ID(divider, (math_error))

CAF_END_TYPE_ID_BLOCK(divider)

CAF_ERROR_CODE_ENUM(math_error)

Default Error Codes

The enum type sec (for System Error Code) provides many error codes for common failures in actor systems:

/// SEC stands for "System Error Code". This enum contains error codes for
/// ::actor_system and its modules.
enum class sec : uint8_t {
  /// No error.
  none = 0,
  /// Indicates that an actor dropped an unexpected message.
  unexpected_message = 1,
  /// Indicates that a response message did not match the provided handler.
  unexpected_response,
  /// Indicates that the receiver of a request is no longer alive.
  request_receiver_down,
  /// Indicates that a request message timed out.
  request_timeout,
  /// Indicates that requested group module does not exist.
  no_such_group_module = 5,
  /// Unpublishing or connecting failed: no actor bound to given port.
  no_actor_published_at_port,
  /// Connecting failed because a remote actor had an unexpected interface.
  unexpected_actor_messaging_interface,
  /// Migration failed because the state of an actor is not serializable.
  state_not_serializable,
  /// An actor received an unsupported key for `('sys', 'get', key)` messages.
  unsupported_sys_key,
  /// An actor received an unsupported system message.
  unsupported_sys_message = 10,
  /// A remote node disconnected during CAF handshake.
  disconnect_during_handshake,
  /// Tried to forward a message via BASP to an invalid actor handle.
  cannot_forward_to_invalid_actor,
  /// Tried to forward a message via BASP to an unknown node ID.
  no_route_to_receiving_node,
  /// Middleman could not assign a connection handle to a broker.
  failed_to_assign_scribe_from_handle,
  /// Middleman could not assign an acceptor handle to a broker.
  failed_to_assign_doorman_from_handle = 15,
  /// User requested to close port 0 or to close a port not managed by CAF.
  cannot_close_invalid_port,
  /// Middleman could not connect to a remote node.
  cannot_connect_to_node,
  /// Middleman could not open requested port.
  cannot_open_port,
  /// A C system call in the middleman failed.
  network_syscall_failed,
  /// A function received one or more invalid arguments.
  invalid_argument = 20,
  /// A network socket reported an invalid network protocol family.
  invalid_protocol_family,
  /// Middleman could not publish an actor because it was invalid.
  cannot_publish_invalid_actor,
  /// A remote spawn failed because the provided types did not match.
  cannot_spawn_actor_from_arguments,
  /// Serialization failed because there was not enough data to read.
  end_of_stream,
  /// Serialization failed because no CAF context is available.
  no_context = 25,
  /// Serialization failed because CAF misses run-time type information.
  unknown_type,
  /// Serialization of actors failed because no proxy registry is available.
  no_proxy_registry,
  /// An exception was thrown during message handling.
  runtime_error,
  /// Linking to a remote actor failed because actor no longer exists.
  remote_linking_failed,
  /// Subscribing to a stream failed because it was invalid.
  invalid_stream = 30,
  /// Subscribing to a stream failed because it can only be subscribed to once.
  cannot_resubscribe_stream,
  /// A stream was aborted by the hosting actor, usually because it terminated.
  stream_aborted,
  /// A function view was called without assigning an actor first.
  bad_function_call = 40,
  /// Feature is disabled in the actor system config.
  feature_disabled,
  /// Failed to open file.
  cannot_open_file,
  /// A socket descriptor argument is invalid.
  socket_invalid,
  /// A socket became disconnected from the remote host (hang up).
  socket_disconnected,
  /// An operation on a socket (e.g. `poll`) failed.
  socket_operation_failed = 45,
  /// A resource is temporarily unavailable or would block.
  unavailable_or_would_block,
  /// Connection refused because of incompatible CAF versions.
  incompatible_versions,
  /// Connection refused because of incompatible application IDs.
  incompatible_application_ids,
  /// Received a malformed message from another node.
  malformed_message,
  /// The middleman closed a connection because it failed to serialize or
  /// deserialize a payload.
  serializing_basp_payload_failed = 50,
  /// The middleman closed a connection to itself or an already connected node.
  redundant_connection,
  /// Resolving a path on a remote node failed.
  remote_lookup_failed,
  /// Serialization failed because actor_system::tracing_context is null.
  no_tracing_context,
  /// No request produced a valid result.
  all_requests_failed,
  /// Deserialization failed because an invariant got violated after reading
  /// the content of a field.
  field_invariant_check_failed = 55,
  /// Deserialization failed because a setter rejected the input.
  field_value_synchronization_failed,
  /// Deserialization failed because the source announced an invalid type.
  invalid_field_type,
  /// Serialization failed because a type was flagged as unsafe message type.
  unsafe_type,
  /// Serialization failed because a save callback returned `false`.
  save_callback_failed,
  /// Deserialization failed because a load callback returned `false`.
  load_callback_failed = 60,
  /// Converting between two types failed.
  conversion_failed,
  /// A network connection was closed by the remote side.
  connection_closed,
  /// An operation failed because run-time type information diverged from the
  /// expected type.
  type_clash,
  /// An operation failed because the callee does not implement this
  /// functionality.
  unsupported_operation,
  /// A key lookup failed.
  no_such_key = 65,
  /// An destroyed a response promise without calling deliver or delegate on it.
  broken_promise,
  /// Disconnected from a BASP node after reaching the connection timeout.
  connection_timeout,
  /// Signals that an actor fell behind a periodic action trigger. After raising
  /// this error, an @ref actor_clock stops scheduling the action.
  action_reschedule_failed,
  /// Attaching to an observable failed because the target is invalid.
  invalid_observable,
  /// Attaching to an observable failed because the target already reached its
  /// maximum observer count.
  too_many_observers = 70,
  /// Signals that an operation failed because the target has been disposed.
  disposed,
  /// Failed to open a resource.
  cannot_open_resource,
  /// Received malformed data.
  protocol_error,
  /// Encountered faulty logic in the program.
  logic_error,
};

Default Exit Reasons

A special kind of error codes are exit reasons of actors. These errors are usually fail states set by the actor system itself. The two exceptions are exit_reason::user_shutdown and exit_reason::kill. The former is used in CAF to signalize orderly, user-requested shutdown and can be used by programmers in the same way. The latter terminates an actor unconditionally when used in send_exit, even for actors that override the default handler (see Exit Handler).

/// This error category represents fail conditions for actors.
enum class exit_reason : uint8_t {
  /// Indicates that an actor finished execution without error.
  normal = 0,
  /// Indicates that the exit reason for this actor is unknown, i.e.,
  /// the actor has been terminated and no longer exists.
  unknown,
  /// Indicates that an actor pool unexpectedly ran out of workers.
  out_of_workers,
  /// Indicates that an actor was forced to shutdown by a user-generated event.
  user_shutdown,
  /// Indicates that an actor was killed unconditionally.
  kill,
  /// Indicates that an actor finished execution because a connection
  /// to a remote link was closed unexpectedly.
  remote_link_unreachable,
  /// Indicates that an actor was killed because it became unreachable.
  unreachable
};