Terminal failures that a caller can act on programmatically are raised
as classed conditions. Each inherits "mizu_error" (alongside "error"
and "condition"), with a subclass that names the failure. Handlers
dispatch with tryCatch(..., mizu_error_worker_died = ...) or test with
inherits() instead of matching message text. Messages are not API and
can be reworded. The class vectors and fields below are API.
Details
The subclasses, where they are raised, and the structured fields they carry as condition elements:
mizu_error_submit_timeout—mizu_submit()on.timeoutexpiry with the injection ring of the submitter still full.mizu_error_slots_exhausted—mizu_submit()andmizu_map()when every result slot in the subrange of the submitter is already outstanding. Collect or cancel before resubmitting.mizu_error_stopped—mizu_submit(),mizu_map()andmizu_pool_attach()against a pool that was stopped or whose owner process died.mizu_error_cancelled—mizu_collect()on a task that was cancelled or whose pool was stopped.mizu_error_worker_died—mizu_collect()on a task whose executing worker died. Fieldsslot(worker registry slot, 0-based as inmizu_pool_dump()) andpid: the claimant record of the result slot, read at collect time. This is informational, racy against slot reuse exactly asmizu_pool_dump()is, andNAwhere no claim was recorded.mizu_map()signals this class again with the lost elements as an additionalelementsfield: a two-column matrix of inclusivelo, hiranges, runner-granular and conservative (see the Errors section ofmizu_map()).mizu_error_startup—mizu_channel(),mizu_pool()andmizu_spawn_workers()when a child process fails to attach withinstartup_timeout.mizu_error_shm— shared-memory region create or open failure anywhere on the surface. Fieldbytes: the requested size of a region that was not created,NAwhen a region was not opened.mizu_error_python_payload—mizu_recv()ormizu_recv_batch()on a channel message written in a language-private stream (a pymizu codec or pickle payload) that this reader cannot interpret. The portable interchange subset crosses; the declined message is consumed, so the channel keeps flowing.mizu_error_not_portable—mizu_send()on a channel whose peer is a foreign-language process, of a value outside the portable interchange subset (a named atomic vector, an environment, a closure, an S4 object, an ordered factor, a data frame subclass, and the like). Fieldspath(where in the value the walk declined),reason, andremedy(a one-line rewrite where one exists, elsecharacter(0)).mizu_error_remote— never raised by mizu itself: the value a channel receive returns for a remote error stream, most commonly a peer process whose expression errored (the peer shims send one before exit, on every channel). Fieldsremote_type(the most-specific class of the original error),message,detail(the call or traceback text), andindex(the 1-based element index) when the remote error carries one. Test withmizu_is_remote_error(); raise withmizu_raise().
Errors of misuse (unnamed task arguments, out-of-range slots, operations on a closed handle) stay plain errors: the classed hierarchy covers the outcomes that a running system produces, not programming mistakes.
Raised mizu_error conditions are distinct from sentinels (class
mizu_sentinel, returned by mizu_send(), mizu_recv() and
mizu_collect()). A sentinel is an ordinary return value that tags a
terminal state on the hot path, not a signalled condition. See
mizu_is_sentinel().
Which discipline applies follows the shape of the call. The verbs that
move payloads and wait with a bound — mizu_send(), mizu_recv(),
mizu_collect(), mizu_map() — return sentinels for transport states.
These are: not yet (mizu_timeout), not now (mizu_full), stream over
(mizu_closed, mizu_peer_gone). Their caller is a loop, and these are
its normal outcomes. Conditions are raised where a request failed for
good. Constructors and mizu_submit(), whose return is a handle the
next line uses, raise on every failure. mizu_collect() raises when the
value can never arrive: the own error of the task re-signalled,
mizu_error_cancelled, mizu_error_worker_died. A sentinel invites the
next iteration of the loop. A condition means stop and deal with it.
Task error transport
A task's own error, re-signalled by mizu_collect() (and
mizu_collect_any() / mizu_collect_all()), is a transport condition
built on the worker at publish time. The caught condition itself never
crosses, so a condition that cannot be serialized can never kill the
worker. The transport condition carries the original classes, the raw
message field (custom conditionMessage() methods are bypassed;
the message is truncated past its share of the result slot's inline
budget), call, and every named field the compact payload codec can
carry within that budget, in the priority order message, call,
fields, then dropped_fields. Fields the codec cannot carry
(environments, closures, S4 objects, ALTREP vectors, external
pointers) and fields past the remaining budget are dropped and named
in a dropped_fields field, absent when nothing was dropped. Only
the named elements of a condition are considered: an unnamed element
cannot be named in dropped_fields and is dropped silently.