wasmerio/wasmer · critical

wasix linker bootstrap invariant violated: expected exactly

Error message

wasix linker bootstrap invariant violated: expected exactly one DL bus subscriber on each sender (pending_operation rx={op_rx}, barrier rx={barrier_rx}); `LinkerShared::bootstrap_exclusive_write_then` must only run during main `Linker::new` finalization before additional instance groups attach receivers

What it means

This is an internal bootstrap invariant check in the WASIX dynamic-linking (DL) machinery. `bootstrap_exclusive_write_then` is only safe to run while exactly one instance group (the main group created by `Linker::new`) is subscribed to each DL broadcast bus (`send_pending_operation` and `send_pending_operation_barrier`). If either sender reports more than one receiver, it means a second instance group attached receivers before bootstrap exclusive writes finished, so the exclusive-write contract is broken and the library panics.

Source

Thrown at lib/wasix/src/state/linker/sync/linker_shared.rs:63

impl LinkerShared {
    /// Wraps freshly constructed [`LinkerState`] for the owning process/module tree (initially only
    /// the main [`super::super::Linker::new`] path).
    pub(in crate::state::linker) fn new(linker_state: LinkerState) -> Self {
        Self {
            linker_state: Arc::new(RwLock::new(linker_state)),
            topology_coordinator: TopologyCoordinator::new(),
            dl_operation_pending: Arc::new(AtomicBool::new(false)),
        }
    }

    /// Panics unless both DL buses have exactly one receiver — validates main-group bootstrap before
    /// exclusive writes (see [`Self::bootstrap_exclusive_write_then`]).
    fn assert_exactly_one_dl_bus_subscriber(ls: &LinkerState) {
        let op_rx = ls.send_pending_operation.rx_count();
        let barrier_rx = ls.send_pending_operation_barrier.rx_count();
        if op_rx != 1 || barrier_rx != 1 {
            panic!(
                "wasix linker bootstrap invariant violated: expected exactly one DL bus subscriber \
                 on each sender (pending_operation rx={op_rx}, barrier rx={barrier_rx}); \
                 `LinkerShared::bootstrap_exclusive_write_then` must only run during main \
                 `Linker::new` finalization before additional instance groups attach receivers"
            );
        }
    }

    /// Exclusive [`LinkerState`] write for main linker bootstrap only.
    ///
    /// # Safety
    ///
    /// Must run only while exactly one instance group has subscribed to both DL buses (verified
    /// after the lock is taken — mismatch panics in release builds). Caller must respect instance-group /
    /// linker lock ordering used in [`super::super::Linker::new`].
    pub(in crate::state::linker) unsafe fn bootstrap_exclusive_write_then<R>(
        &self,
        f: impl FnOnce(&mut LinkerState) -> R,

View on GitHub (pinned to 8c4b9ee9d3)

Solutions

  1. Ensure all `bootstrap_exclusive_write_then` calls happen only inside the main `Linker::new` finalization path, before any instance group is created
  2. Move instance-group creation (spawn/prepare_for_instance_group) after linker bootstrap completes, behind the topology coordinator so it cannot race bootstrap writes
  3. Inspect the panic's rx counts to see which bus has extra receivers and find which code path attaches receivers early
  4. If you patched wasix internals, audit receiver attach points to confirm they only run after bootstrap

Example fix

// before: attach instance group then bootstrap write
let group = linker.prepare_for_instance_group(...);
linker.shared.bootstrap_exclusive_write_then(|ls| { /* ... */ });
// after: bootstrap first, then attach groups
linker.shared.bootstrap_exclusive_write_then(|ls| { /* ... */ });
let group = linker.prepare_for_instance_group(...);
Defensive patterns

Strategy: validation

Validate before calling

// Before any bootstrap_exclusive_write_then, verify bus subscription counts
let ls = linker.shared.try_read_linker_state()?;
assert_eq!(ls.send_pending_operation.rx_count(), 1);
assert_eq!(ls.send_pending_operation_barrier.rx_count(), 1);

Type guard

fn is_main_group_bootstrap_safe(ls: &LinkerState) -> bool {
    ls.send_pending_operation.rx_count() == 1
        && ls.send_pending_operation_barrier.rx_count() == 1
}

Try / catch

// This is a panic, not a recoverable error — use catch_unwind at the embedder boundary
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
    linker.shared.bootstrap_exclusive_write_then(|ls| { /* ... */ })
}));

Prevention

When it happens

Trigger: Calling `LinkerShared::bootstrap_exclusive_write_then` after additional instance groups have subscribed to the DL buses (e.g. creating instance groups, spawning follower threads/instances, or calling `prepare_for_instance_group`/`create_instance_group` before all bootstrap writes complete). Also triggered by receiver-count races where a follower group attaches its bus receivers concurrently with `Linker::new` finalization.

Common situations: Embedding code that spawns or attaches extra WASIX instance groups during linker construction; reordering linker initialization so group creation races with `Linker::new`; custom patches or extensions to the linker that perform exclusive writes late in startup.

Related errors


AI-assisted analysis of wasmerio/wasmer@8c4b9ee9d3 (2026-09-01). Data as JSON: /api/errors/a4b77c55a94bfe4b. Report an issue: GitHub.