{"record":{"id":"a14191c8e31feefd","repo":"linera-io/linera-protocol","slug":"failed-to-unwrap-shared-context","errorCode":null,"errorMessage":"Failed to unwrap shared context","messagePattern":"Failed to unwrap shared context","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"linera-service/src/cli/main.rs","lineNumber":943,"sourceCode":"                                }\n                            })\n                            .collect::<Result<_, _>>()?;\n\n                        linera_client::benchmark::Benchmark::run_benchmark(\n                            bps,\n                            chain_clients.clone(),\n                            generators,\n                            transactions_per_block,\n                            health_check_endpoints.clone(),\n                            runtime_in_seconds,\n                            delay_between_chains_ms,\n                            chain_listener,\n                            &shutdown_notifier,\n                        )\n                        .await?;\n\n                        let mut context = std::sync::Arc::try_unwrap(shared_context)\n                            .map_err(|_| anyhow::anyhow!(\"Failed to unwrap shared context\"))?\n                            .into_inner();\n                        context\n                            .wrap_up_benchmark(chain_clients, close_chains, wrap_up_max_in_flight)\n                            .await?;\n                    }\n\n                    BenchmarkCommand::Multi {\n                        options: benchmark_options,\n                        processes,\n                        faucet,\n                        client_state_dir,\n                        delay_between_processes,\n                        cross_wallet_transfers,\n                    } => {\n                        let mut command = BenchmarkCommand::Single {\n                            options: benchmark_options.clone(),\n                        };\n                        let faucet_client = cli_wrappers::Faucet::new(faucet.clone());","sourceCodeStart":925,"sourceCodeEnd":961,"githubUrl":"https://github.com/linera-io/linera-protocol/blob/6c226ddcb332ef55118dc8d0aafbd093d5420899/linera-service/src/cli/main.rs#L925-L961","documentation":"Arc::try_unwrap on the shared ClientContext failed because at least one other Arc clone is still alive. After the benchmark finishes, main.rs needs exclusive ownership (&mut) to run wrap_up_benchmark, but the chain listener or another background task still holds a clone, so the strong count is > 1 at the unwrap point.","triggerScenarios":"The shutdown notifier fired but the listener task (or any task holding Arc<ClientContext>: notification handlers, query-subscription watchers) has not yet observed cancellation and dropped its clone — a race between shutdown signaling and task teardown.","commonSituations":"New background holders of the context added in newer versions that outlive the benchmark; overloaded machines where task teardown lags the shutdown signal; aborting on the unwrap path instead of joining tasks.","solutions":["Ensure every task holding an Arc<ClientContext> clone is joined (or aborted and awaited) before try_unwrap.","Trigger shutdown_notifier, then await the listener task's JoinHandle so its clone is provably dropped.","If the race is benign, retry try_unwrap briefly after signaling shutdown instead of failing immediately.","Longer term, restructure wrap-up so it does not require exclusive ownership (e.g. message-passing to the task that owns the context)."],"exampleFix":"// before: unwrap races against tasks that still hold clones\nlet context = Arc::try_unwrap(shared_context)\n    .map_err(|_| anyhow::anyhow!(\"Failed to unwrap shared context\"))?\n    .into_inner();\n\n// after: signal shutdown, join the holder, then unwrap\nshutdown_notifier.notify_one();\nlet shared_context = listener_handle.await?; // task returns its clone / drops it\nlet context = Arc::try_unwrap(shared_context)\n    .expect(\"all clones dropped after tasks joined\")\n    .into_inner();","handlingStrategy":"retry","validationCode":"if Arc::strong_count(&shared_context) != 1 {\n    // another task still holds the ClientContext — signal and join it first\n    shutdown_notifier.notify_one();\n    listener_handle.abort();\n}","typeGuard":null,"tryCatchPattern":"let context = match Arc::try_unwrap(shared_context) {\n    Ok(ctx) => ctx.into_inner(),\n    Err(ctx) => {\n        tracing::warn!(\"context still shared; waiting for holders to drop\");\n        shutdown_notifier.notify_one();\n        let _ = listener_handle.await; // ensure the clone is dropped\n        Arc::try_unwrap(ctx)\n            .expect(\"all clones dropped after tasks joined\")\n            .into_inner()\n    }\n};","preventionTips":["Keep a registry of every spawned task holding an Arc<ClientContext> clone and join them all before unwrap.","Always await task handles after triggering shutdown — signaling alone does not drop clones.","Debug with Arc::strong_count to find unexpected holders early."],"tags":["rust","arc","concurrency","benchmark","shared-state"],"backgroundTag":"arc-try-unwrap-failed","analyzedSha":"6c226ddcb332ef55118dc8d0aafbd093d5420899","analyzedAt":"2026-08-22T22:49:09.787Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}