{"record":{"id":"a4b77c55a94bfe4b","repo":"wasmerio/wasmer","slug":"wasix-linker-bootstrap-invariant-violated-expecte","errorCode":null,"errorMessage":"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","messagePattern":"wasix linker bootstrap invariant violated: expected exactly one DL bus subscriber on each sender \\(pending_operation rx=(.+?), barrier rx=(.+?)\\); `LinkerShared::bootstrap_exclusive_write_then` must only run during main `Linker::new` finalization before additional instance groups attach receivers","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"lib/wasix/src/state/linker/sync/linker_shared.rs","lineNumber":63,"sourceCode":"\nimpl LinkerShared {\n    /// Wraps freshly constructed [`LinkerState`] for the owning process/module tree (initially only\n    /// the main [`super::super::Linker::new`] path).\n    pub(in crate::state::linker) fn new(linker_state: LinkerState) -> Self {\n        Self {\n            linker_state: Arc::new(RwLock::new(linker_state)),\n            topology_coordinator: TopologyCoordinator::new(),\n            dl_operation_pending: Arc::new(AtomicBool::new(false)),\n        }\n    }\n\n    /// Panics unless both DL buses have exactly one receiver — validates main-group bootstrap before\n    /// exclusive writes (see [`Self::bootstrap_exclusive_write_then`]).\n    fn assert_exactly_one_dl_bus_subscriber(ls: &LinkerState) {\n        let op_rx = ls.send_pending_operation.rx_count();\n        let barrier_rx = ls.send_pending_operation_barrier.rx_count();\n        if op_rx != 1 || barrier_rx != 1 {\n            panic!(\n                \"wasix linker bootstrap invariant violated: expected exactly one DL bus subscriber \\\n                 on each sender (pending_operation rx={op_rx}, barrier rx={barrier_rx}); \\\n                 `LinkerShared::bootstrap_exclusive_write_then` must only run during main \\\n                 `Linker::new` finalization before additional instance groups attach receivers\"\n            );\n        }\n    }\n\n    /// Exclusive [`LinkerState`] write for main linker bootstrap only.\n    ///\n    /// # Safety\n    ///\n    /// Must run only while exactly one instance group has subscribed to both DL buses (verified\n    /// after the lock is taken — mismatch panics in release builds). Caller must respect instance-group /\n    /// linker lock ordering used in [`super::super::Linker::new`].\n    pub(in crate::state::linker) unsafe fn bootstrap_exclusive_write_then<R>(\n        &self,\n        f: impl FnOnce(&mut LinkerState) -> R,","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/wasmerio/wasmer/blob/8c4b9ee9d33fb2068863fbb3d328683e7e6ff7f5/lib/wasix/src/state/linker/sync/linker_shared.rs#L45-L81","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Ensure all `bootstrap_exclusive_write_then` calls happen only inside the main `Linker::new` finalization path, before any instance group is created","Move instance-group creation (spawn/prepare_for_instance_group) after linker bootstrap completes, behind the topology coordinator so it cannot race bootstrap writes","Inspect the panic's rx counts to see which bus has extra receivers and find which code path attaches receivers early","If you patched wasix internals, audit receiver attach points to confirm they only run after bootstrap"],"exampleFix":"// before: attach instance group then bootstrap write\nlet group = linker.prepare_for_instance_group(...);\nlinker.shared.bootstrap_exclusive_write_then(|ls| { /* ... */ });\n// after: bootstrap first, then attach groups\nlinker.shared.bootstrap_exclusive_write_then(|ls| { /* ... */ });\nlet group = linker.prepare_for_instance_group(...);","handlingStrategy":"validation","validationCode":"// Before any bootstrap_exclusive_write_then, verify bus subscription counts\nlet ls = linker.shared.try_read_linker_state()?;\nassert_eq!(ls.send_pending_operation.rx_count(), 1);\nassert_eq!(ls.send_pending_operation_barrier.rx_count(), 1);","typeGuard":"fn is_main_group_bootstrap_safe(ls: &LinkerState) -> bool {\n    ls.send_pending_operation.rx_count() == 1\n        && ls.send_pending_operation_barrier.rx_count() == 1\n}","tryCatchPattern":"// This is a panic, not a recoverable error — use catch_unwind at the embedder boundary\nlet result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {\n    linker.shared.bootstrap_exclusive_write_then(|ls| { /* ... */ })\n}));","preventionTips":["Only call bootstrap_exclusive_write_then inside Linker::new finalization","Create instance groups strictly after linker bootstrap completes","Serialize group attachment behind the topology coordinator","Log rx_count values during startup to catch early attachers in CI"],"tags":["wasix","linker","dynamic-linking","invariant-violation","concurrency"],"backgroundTag":"linker-bootstrap-invariant-violated","analyzedSha":"8c4b9ee9d33fb2068863fbb3d328683e7e6ff7f5","analyzedAt":"2026-09-01T23:06:31.009Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}