{"record":{"id":"a8edf9e5c1bea245","repo":"tonhowtf/omniget","slug":"send-cancelled-while-paused","errorCode":null,"errorMessage":"Send cancelled while paused","messagePattern":"Send cancelled while paused","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"info","filePath":"src-tauri/omniget-core/src/platforms/p2p.rs","lineNumber":319,"sourceCode":"    tracing::info!(\n        \"[p2p] transferring: {} ({} bytes)\",\n        session.file_name,\n        session.file_size\n    );\n\n    let mut file = File::open(&session.file_path).await?;\n    let mut buf = vec![0u8; CHUNK_SIZE];\n    let mut sent: u64 = 0;\n\n    loop {\n        if cancel.is_cancelled() {\n            anyhow::bail!(\"Send cancelled during transfer\");\n        }\n\n        while session.paused.load(std::sync::atomic::Ordering::Relaxed) {\n            tokio::time::sleep(std::time::Duration::from_millis(100)).await;\n            if cancel.is_cancelled() {\n                anyhow::bail!(\"Send cancelled while paused\");\n            }\n        }\n\n        let n = file.read(&mut buf).await?;\n        if n == 0 {\n            break;\n        }\n\n        write_half.write_all(&buf[..n]).await?;\n        sent += n as u64;\n\n        *session.sent_bytes.lock().await = sent;\n        if session.file_size > 0 {\n            *session.progress.lock().await = (sent as f64 / session.file_size as f64) * 100.0;\n        }\n    }\n\n    write_half.flush().await?;","sourceCodeStart":301,"sourceCodeEnd":337,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/platforms/p2p.rs#L301-L337","documentation":"In the P2P transfer sender loop (p2p.rs run_sender), while the session is paused the sender polls every 100ms and checks the shared CancellationToken. If cancellation fires during the pause, the sender aborts with this error instead of resuming reading the file. It exists so a cancelled send does not hang forever while paused.","triggerScenarios":"Calling cancel on the transfer token while session.paused is true; e.g. the receiver disconnects or the user aborts a paused send via the cancellation token passed to run_sender.","commonSituations":"User pauses a P2P file send and then closes the app/cancels the transfer; peer triggers cancellation while the sender is parked in the pause-wait loop.","solutions":["Treat this as an expected abort: catch it and clean up the session/socket rather than retrying.","If the send should continue, avoid cancelling while paused — resume the session first, then cancel if needed.","Check cancel.is_cancelled() before pausing or before entering the loop so the state transition is handled explicitly."],"exampleFix":"// before\nloop {\n    while session.paused.load(Ordering::Relaxed) {\n        tokio::time::sleep(Duration::from_millis(100)).await;\n    }\n    ...\n}\n// after\n// select on cancellation so pause and cancel are handled uniformly\ntokio::select! {\n    _ = cancel.cancelled() => anyhow::bail!(\"Send cancelled\"),\n    _ = async {\n        while session.paused.load(Ordering::Relaxed) {\n            tokio::time::sleep(Duration::from_millis(100)).await;\n        }\n    } => {}\n}","handlingStrategy":"try-catch","validationCode":"// before sending\nif cancel.is_cancelled() { return Err(anyhow!(\"Send cancelled\")); }","typeGuard":null,"tryCatchPattern":"match run_sender(...).await {\n    Err(e) if e.to_string().contains(\"cancelled\") => cleanup_session(&session),\n    other => other?,\n}","preventionTips":["Resume the session before cancelling the token","Check cancellation state before pausing","Distinguish user-abort from transfer errors in your error handling"],"tags":["p2p","cancellation","async","tokio"],"backgroundTag":"operation-cancelled","analyzedSha":"8600b91f4246848bac346874daa9e61c1fc5677a","analyzedAt":"2026-09-12T14:29:19.317Z","contentChangedAt":"2026-09-12T14:29:19.317Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}