{"record":{"id":"acc8f5f5a19b230c","repo":"wasmerio/wasmer","slug":"internal-error-more-than-one-synchronized-link-op","errorCode":null,"errorMessage":"Internal error: more than one synchronized link operation active","messagePattern":"Internal error: more than one synchronized link operation active","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"lib/wasix/src/state/linker/sync/linker_shared.rs","lineNumber":229,"sourceCode":"    ) {\n        trace!(?op, \"Synchronizing link operation\");\n\n        let num_groups = linker_state_write_lock.send_pending_operation.rx_count();\n\n        if num_groups <= 1 {\n            trace!(\"No other living instance groups, nothing to do\");\n            drop(topology);\n            return;\n        }\n\n        let barrier = Arc::new(Barrier::new(num_groups));\n        // Single-flight barrier envelope (bus depth is one intentionally).\n        if linker_state_write_lock\n            .send_pending_operation_barrier\n            .try_broadcast(barrier.clone())\n            .is_err()\n        {\n            panic!(\"Internal error: more than one synchronized link operation active\")\n        }\n\n        // Wake followers so syscall paths re-enter cooperative DL helpers promptly.\n        self.dl_operation_pending.store(true, Ordering::SeqCst);\n\n        trace!(\"Signalling wasix threads to wake up\");\n        for thread in wasi_process\n            .all_threads()\n            .into_iter()\n            .filter(|tid| *tid != self_thread_id)\n        {\n            wasi_process.signal_thread(&thread, wasmer_wasix_types::wasi::Signal::Sigwakeup);\n        }\n\n        trace!(%num_groups, \"Waiting at barrier\");\n        barrier.wait();\n\n        trace!(\"All threads now processing dl op\");","sourceCodeStart":211,"sourceCodeEnd":247,"githubUrl":"https://github.com/wasmerio/wasmer/blob/8c4b9ee9d33fb2068863fbb3d328683e7e6ff7f5/lib/wasix/src/state/linker/sync/linker_shared.rs#L211-L247","documentation":"`synchronize_link_operation` broadcasts a rendezvous barrier to all instance groups via `send_pending_operation_barrier.try_broadcast`. The barrier bus is intentionally depth-one (single-flight): only one synchronized link operation may be in flight at a time. If `try_broadcast` fails, a previous operation's barrier message was never consumed (or a second operation is concurrently active), which is an unrecoverable internal invariant breach, so the library panics.","triggerScenarios":"Starting a new `synchronize_link_operation` while a previous barrier epoch is still unconsumed on the barrier bus (e.g. a follower crashed or hung between the two barrier waits); two threads entering `synchronize_link_operation` concurrently due to a missing TopologyToken; retrying the call after a partial failure.","commonSituations":"Hung or cancelled WASIX threads that left the previous DL operation half-finished; topology-token misuse in custom linker code; bug fixes or partial upgrades of wasix internals that allow overlapping link operations.","solutions":["Verify every `synchronize_link_operation` caller holds the TopologyToken acquired via `acquire_topology_token` so calls are serialized","Check for hung/panicking follower threads that never reached the barrier and left stale messages on the barrier bus","Restart the WASIX process — the single-flight bus cannot be reconciled after this panic","If you maintain wasix, ensure followers always drain `recv_pending_operation_barrier` even on error paths"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Only start a link op while holding the topology token and no op is pending\nif !linker.shared.dl_operation_pending_load() {\n    // safe window to enter synchronize_link_operation\n}","typeGuard":"fn link_operation_idle(pending: &AtomicBool) -> bool {\n    !pending.load(Ordering::SeqCst)\n}","tryCatchPattern":"let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {\n    linker.shared.synchronize_link_operation(token, op, guard, &mut group, &proc, &tid);\n}));\nif result.is_err() { /* a stale epoch is in flight: restart the process tree */ }","preventionTips":["Always hold the TopologyToken when calling synchronize_link_operation","Ensure followers always drain the barrier bus, even on error paths","Never retry a partially completed link operation","Add watchdogs for follower threads so hung epochs are detected early"],"tags":["wasix","linker","dynamic-linking","concurrency","invariant-violation"],"backgroundTag":"concurrent-link-operation","analyzedSha":"8c4b9ee9d33fb2068863fbb3d328683e7e6ff7f5","analyzedAt":"2026-09-01T23:06:31.009Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}