{"record":{"id":"fa44d8a2a3bfe383","repo":"vectordotdev/vector","slug":"poisoned","errorCode":null,"errorMessage":"poisoned","messagePattern":"poisoned","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/components/validation/sync.rs","lineNumber":217,"sourceCode":"\nimpl TaskCoordinator<Configuring> {\n    /// Attaches a new child to the wait group that tracks when tasks have started.\n    pub fn track_started(&self) -> WaitGroupChild {\n        self.state.tasks_started.add_child()\n    }\n\n    /// Attaches a new child to the wait group that tracks when tasks have completed.\n    pub fn track_completed(&self) -> WaitGroupChild {\n        self.state.tasks_completed.add_child()\n    }\n\n    /// Registers a handle that will be notified when shutdown is triggered.\n    pub fn register_for_shutdown(&self) -> WaitHandle {\n        let (trigger, handle) = WaitTrigger::new();\n        self.state\n            .shutdown_triggers\n            .lock()\n            .expect(\"poisoned\")\n            .push(trigger);\n        handle\n    }\n\n    /// Waits for all tasks to have marked that they have started.\n    pub async fn started(self) -> TaskCoordinator<Started> {\n        let Configuring {\n            mut tasks_started,\n            tasks_completed,\n            shutdown_triggers,\n        } = self.state;\n\n        tasks_started.wait_for_children().await;\n        trace!(\"All coordinated tasks reported as having started.\");\n\n        TaskCoordinator {\n            state: Started {\n                tasks_completed: Some(tasks_completed),","sourceCodeStart":199,"sourceCodeEnd":235,"githubUrl":"https://github.com/vectordotdev/vector/blob/bdb87aeaa4c4ff27c0ba643c1c77b21bf2ef4013/src/components/validation/sync.rs#L199-L235","documentation":"register_for_shutdown locks the TaskCoordinator's shared Mutex of shutdown triggers and asserts the lock isn't poisoned. The lock is only poisoned if another thread panicked while holding it (e.g. during WaitTrigger::new or Vec push). This panic indicates a prior panic somewhere in coordinator-managed code, surfaced here as a lock error.","triggerScenarios":"Calling register_for_shutdown (from spawn_input_http_server, spawn_grpc_server, spawn_component_topology, or into_collector) after some thread panicked while holding the shutdown_triggers mutex during coordinator setup/teardown.","commonSituations":"An earlier panic inside the validation framework's setup (e.g. topology construction) leaving the mutex poisoned; cascading panics in tests where the first failure is masked by this 'poisoned' panic.","solutions":["Look for the ORIGINAL panic earlier in the test output — the poisoning panic is the root cause, not this one.","Replace .expect(\"poisoned\") with .unwrap_or_else(PoisonError::into_inner) during debugging to proceed and expose the state.","Avoid panicking while holding the coordinator's mutexes (keep lock scopes minimal, clone data out before fallible work)."],"exampleFix":"// before\n.lock().expect(\"poisoned\").push(trigger);\n// after\n.lock().unwrap_or_else(PoisonError::into_inner).push(trigger);","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match self.state.shutdown_triggers.lock() {\n    Ok(mut triggers) => triggers.push(trigger),\n    Err(e) => panic!(\"coordinator mutex poisoned by earlier panic: {e}\"),\n}","preventionTips":["Always hunt for the FIRST panic in the output — 'poisoned' is always secondary.","Keep lock scopes minimal; never run fallible/panicking code while holding coordinator locks.","Use PoisonError::into_inner recovery temporarily while debugging cascades."],"tags":["mutex","poison","sync"],"backgroundTag":"thread-interrupted","analyzedSha":"bdb87aeaa4c4ff27c0ba643c1c77b21bf2ef4013","analyzedAt":"2026-09-16T02:53:35.741Z","contentChangedAt":"2026-09-16T02:53:35.741Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}