{"record":{"id":"c602656ef7f8805e","repo":"crossbeam-rs/crossbeam","slug":"dropped-selectedoperation-without-completing-the-operation","errorCode":null,"errorMessage":"dropped `SelectedOperation` without completing the operation","messagePattern":"dropped `SelectedOperation` without completing the operation","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crossbeam-channel/src/select.rs","lineNumber":1375,"sourceCode":"        assert!(\n            r.addr() == self.addr,\n            \"passed a receiver that wasn't selected\",\n        );\n        let res = unsafe { channel::read(r, &mut self.token) };\n        mem::forget(self);\n        res.map_err(|_| RecvError)\n    }\n}\n\nimpl fmt::Debug for SelectedOperation<'_> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.pad(\"SelectedOperation { .. }\")\n    }\n}\n\nimpl Drop for SelectedOperation<'_> {\n    fn drop(&mut self) {\n        panic!(\"dropped `SelectedOperation` without completing the operation\");\n    }\n}\n","sourceCodeStart":1357,"sourceCodeEnd":1378,"githubUrl":"https://github.com/crossbeam-rs/crossbeam/blob/38dacb462261fcd64edcb308aed9cbf95c8c82c3/crossbeam-channel/src/select.rs#L1357-L1378","documentation":"`SelectedOperation` represents an in-progress select: once `select()` returned an operation, you must finish it by calling `send()`, `recv()`, or `recv_ref()` on it. `SelectedOperation` deliberately has no infallible Drop impl, so dropping it without completing the operation is treated as a bug and panics, because the channel's internal state was already marked as selected and would be left inconsistent.","triggerScenarios":"Using `?` or early `return`/`break` in the code path between `sel.select()` and the `send()`/`recv()` completion call; unwinding a panic raised inside the selected-operation handling block; using `std::mem::forget`-like patterns or conditionally skipping the completion call.","commonSituations":"Error propagation (`?`) in a function whose body contains the select operation; panics inside a closure passed around the `SelectedOperation`; refactors that reorder code so the completion call is no longer reached on all paths.","solutions":["Ensure every code path that obtains a `SelectedOperation` calls `send()`/`recv()` on it exactly once","Move error-returning code before the `select()` call, or wrap the completion in an inner scope so the operation is always consumed before `?`/return","Use `select!` macro instead of the manual API — it completes the operation for you","Catch and resume-unwrap is NOT viable for this panic; restructure instead"],"exampleFix":"// before\nlet oper = sel.select();\nlet val = compute()?; // early return drops `oper` -> panic\noper.send(&tx, val);\n\n// after\nlet val = compute()?; // fallible work BEFORE selecting\nlet oper = sel.select();\noper.send(&tx, val); // operation always completed","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"fn completed(op: Option<&SelectedOperation<'_>>) -> bool { op.is_none() } // ensure the operation is consumed via send/recv before its scope ends","tryCatchPattern":"// Cannot be caught; restructure instead:\n// do fallible work BEFORE sel.select(), then complete the operation immediately","preventionTips":["Never use `?` or early return between select() and send()/recv()","Complete the operation in the same scope it was created","Prefer the select! macro over the manual SelectedOperation API"],"tags":["rust","crossbeam-channel","panic","drop","select"],"backgroundTag":"invalid-state-transition","analyzedSha":"38dacb462261fcd64edcb308aed9cbf95c8c82c3","analyzedAt":"2026-09-13T03:24:01.537Z","contentChangedAt":"2026-09-13T03:24:01.537Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}