{"record":{"id":"11d0bc7ac3b190da","repo":"cloudflare/quiche","slug":"tokio-task-id-already-in-use-id","errorCode":null,"errorMessage":"tokio task ID already in use: {id}","messagePattern":"tokio task ID already in use: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"task-killswitch/src/lib.rs","lineNumber":194,"sourceCode":"    fn add_task_if(\n        &self, handle: AbortHandle, cond: impl FnOnce() -> bool,\n    ) -> Result<(), AbortHandle> {\n        use dashmap::Entry::*;\n        let id = handle.id();\n\n        match self.tasks.entry(id) {\n            Vacant(e) => {\n                if !cond() {\n                    return Err(handle);\n                }\n                e.insert(TaskEntry::Handle(handle));\n            },\n            Occupied(e) if matches!(e.get(), TaskEntry::Tombstone) => {\n                // Task was removed before it was added. Clear the map entry and\n                // drop the handle.\n                e.remove();\n            },\n            Occupied(_) => panic!(\"tokio task ID already in use: {id}\"),\n        }\n\n        Ok(())\n    }\n\n    fn remove_task(&self, id: task::Id) {\n        use dashmap::Entry::*;\n        match self.tasks.entry(id) {\n            Vacant(e) => {\n                // Task was not added yet, set a tombstone instead.\n                e.insert(TaskEntry::Tombstone);\n            },\n            Occupied(e) if matches!(e.get(), TaskEntry::Tombstone) => {},\n            Occupied(e) => {\n                e.remove();\n            },\n        }\n    }","sourceCodeStart":176,"sourceCodeEnd":212,"githubUrl":"https://github.com/cloudflare/quiche/blob/9f96daa2c22a4468b0036fb0a0a3894eee6498b8/task-killswitch/src/lib.rs#L176-L212","documentation":"task-killswitch's add_task_if panics when a tokio task::Id is inserted into the registry while a live (non-tombstone) entry with that same ID already exists. Task IDs should be unique per spawned task, so this indicates a bookkeeping bug: the same ID was added twice without being removed, i.e. an internal invariant violation of the registry.","triggerScenarios":"Calling add_task_if (via the killswitch tracking wrapper) with a task::Id that already maps to a live TaskEntry; re-registering a task handle without a prior remove_task; racing registration logic that reuses IDs.","commonSituations":"Custom task-management code layered on the killswitch that spawns and re-registers handles manually, tests that add the same mocked task ID twice, upstream tokio behavior changes causing ID reuse.","solutions":["Always pair every add_task_if with a remove_task (e.g. via the provided JoinHandle wrappers) so IDs are freed before reuse","Check the map before inserting; treat an existing live entry as a bug and log/replace it deliberately","Update task-killswitch / tokio to compatible versions if ID reuse behavior changed","If the duplicate is intentional (task respawned), remove the stale entry first"],"exampleFix":"// before\nregistry.add_task_if(id, handle, pred)?;\nregistry.add_task_if(id, new_handle, pred)?; // panics: id still live\n// after\nregistry.add_task_if(id, handle, pred)?;\nregistry.remove_task(id);\nregistry.add_task_if(id, new_handle, pred)?;","handlingStrategy":"try-catch","validationCode":"// Rust: check before registering\nif registry.contains_live_task(&id) {\n    registry.remove_task(id);\n}\nregistry.add_task_if(id, handle, pred)?;","typeGuard":"fn is_registered(map: &HashMap<task::Id, TaskEntry>, id: &task::Id) -> bool {\n    matches!(map.get(id), Some(TaskEntry::Live(_)))\n}","tryCatchPattern":"// task-killswitch panics on duplicate ID; there is no catchable error.\n// Guard the call site and treat a panic as a bug:\nlet result = std::panic::catch_unwind(|| registry.add_task_if(id, handle, pred));\nif result.is_err() {\n    // duplicate task id: log and recover\n}","preventionTips":["Always pair add_task_if with remove_task via the provided handle wrappers","Never re-register a task ID while its live entry exists","Write tests that spawn/kill/re-spawn tasks through the killswitch API","Keep task-killswitch and tokio versions in sync"],"tags":["tokio","task-management","panic","duplicate-key"],"backgroundTag":"identifier-already-in-use","analyzedSha":"9f96daa2c22a4468b0036fb0a0a3894eee6498b8","analyzedAt":"2026-09-08T11:27:09.536Z","contentChangedAt":"2026-09-08T11:27:09.536Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}