Skip to content

Errors and limits

Reference

The crate’s error surface is four types, and every failure is returned, never panicked inside the library.

pub struct NodeFault {
pub node: &'static TaskNode,
pub kind: FaultKind,
}

Display names the node and the cause, so {fault} is a complete escalation message. Four distinct bring-up causes arrive as one typed fault, and each prints something you can act on:

att-estimator: ready-dep imu-reader did not assert within 2000ms

Debug is derived (.unwrap() / .expect() work), and defmt::Format arrives with the defmt feature.

FaultKindwhat it namesreturned by
ExecutorSlotEmptyan executor: slot still empty at the deadlinestart, start_node, cascades, pool growth
ResourceMissinga resources: slot, or an unprovided divisible budget, unfilled at the deadlinesame
ReadyDepTimeout { dep }a ready dep that never assertedsame
Spawn(SpawnError)the executor refused the spawn (full task pool, busy slot)same
ShutdownTimeouta node that missed the shutdown-ack deadline (its divisible shares are released either way)stop_node, teardown, apply_control, run_pools (a wedged shrink)
  • Aborted: the cancellation result of run_cancellable / run_cancellable_acked, handed to the worker’s body.
  • Resumed: the pause-cycle result of run_pausable, handed to the worker’s body. Not a failure: the park is already over, and the next loop iteration is the fresh cycle.
  • ControlQueueFull: what try_request_control returns when the mailbox is full. The async request_control instead waits for capacity; neither drops a command.

SpawnError is re-used from embassy-executor and only appears inside FaultKind::Spawn.

knobdefaultoverride
shutdown-ack timeout (window starts when the node is signalled)2 sack_timeout: per node
pre-spawn gate wait (executor slot, resources, ready deps): one shared budget per node in a start() wave, per gate in the single-node verbs100 msslot_timeout:
control mailbox depth4fixed
trace registries4 executors; graphs register onto a linked chain, any numberfixed
fresh-spawn gracea spawn counts as a beatnone needed
  • 256 nodes per graph (pool members included): all graph indices are u8, keeping the dep table and order arrays byte-sized on flash-constrained targets.
  • Pool bounds: min <= max <= member count, values fitting u8. The member count itself stays a literal (it determines how much is emitted).
  • One compose site per binary; one set of trace hook symbols per binary (the unnamed graph carries them).
  • pool_size > 1 cannot combine with lend, consume or divisible resources (one slot, one value or claimant).
  • Veto gates (feature veto): at most 32 writers per gate, one spelling per gate; the target must be a VetoGate with a slot per writer.
  • Budgets (feature budget): one slot per declaring node and pool member, inside the 256-slot cap.

Bring-up faults from run() are typically escalated hard (a panic! into a hardware-watchdog reset): the graph is the product; if it cannot come up, nothing should run. Shutdown faults name a wedged task and are the more interesting case: retry, log and continue degraded, or reset, as the domain demands. The library’s contract ends at returning the fault with provenance.