{"record":{"id":"0442e8fa777dfd45","repo":"tonhowtf/omniget","slug":"send-cancelled-while-waiting-for-receiver","errorCode":null,"errorMessage":"Send cancelled while waiting for receiver","messagePattern":"Send cancelled while waiting for receiver","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"info","filePath":"src-tauri/omniget-core/src/platforms/p2p.rs","lineNumber":273,"sourceCode":"\n    write_half\n        .write_all(format!(\"SEND {}\\n\", session.code).as_bytes())\n        .await?;\n    write_half.flush().await?;\n\n    let response = read_line(&mut reader).await?;\n    check_relay_error(&response)?;\n    if response != \"WAIT\" {\n        anyhow::bail!(\"Unexpected relay response: {}\", response);\n    }\n\n    *session.status.lock().await = \"waiting_for_receiver\".to_string();\n    tracing::info!(\"[p2p] waiting for receiver... code: {}\", session.code);\n\n    let ready = tokio::select! {\n        line = read_line(&mut reader) => line?,\n        _ = cancel.cancelled() => {\n            anyhow::bail!(\"Send cancelled while waiting for receiver\");\n        }\n    };\n\n    check_relay_error(&ready)?;\n    if ready != \"READY\" {\n        anyhow::bail!(\"Unexpected relay response: {}\", ready);\n    }\n\n    *session.status.lock().await = \"connected\".to_string();\n    tracing::info!(\"[p2p] receiver connected\");\n\n    let header = format!(\"{}\\n{}\\n\", session.file_name, session.file_size);\n    write_half.write_all(header.as_bytes()).await?;\n    write_half.flush().await?;\n\n    let ok_response = tokio::select! {\n        line = read_line(&mut reader) => line?,\n        _ = cancel.cancelled() => {","sourceCodeStart":255,"sourceCodeEnd":291,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/platforms/p2p.rs#L255-L291","documentation":"run_sender waits for the relay's \"READY\" line inside a tokio::select! that races read_line against the cancel token. If cancellation wins, the library aborts with this explicit error instead of a generic one. It is deliberate cooperative cancellation during the wait-for-receiver phase, not a network failure.","triggerScenarios":"Cancelling the CancellationToken passed to run_sender while the sender is still waiting for a receiver to connect (before any \"READY\" line arrives).","commonSituations":"User closes the send dialog while waiting; app shuts down; a UI-level timeout cancels long-idle sessions that never found a receiver.","solutions":["Treat as a benign, user-initiated abort: match on the message and update session status without surfacing a scary error","If auto-retry is desired, create a new cancel token and a fresh session (start_send) — do not reuse the cancelled one","Always cancel cleanly so the relay slot is freed; consider notifying the relay/session teardown on abort"],"exampleFix":"// before\n_ = cancel.cancelled() => {\n    anyhow::bail!(\"Send cancelled while waiting for receiver\");\n}\n// after\n_ = cancel.cancelled() => {\n    *session.status.lock().await = \"cancelled\".to_string();\n    anyhow::bail!(\"Send cancelled while waiting for receiver\");\n}","handlingStrategy":"try-catch","validationCode":"// Only start a send with a live, non-cancelled token\nif cancel.is_cancelled() {\n    anyhow::bail!(\"Refusing to start send with a cancelled token\");\n}","typeGuard":null,"tryCatchPattern":"let result = p2p::start_send(path).await;\nmatch result {\n    Ok(session) => { /* run_sender handles its own cancel errors */ }\n    Err(e) if e.to_string().contains(\"cancelled\") => { /* user aborted: update UI, no error */ }\n    Err(e) => return Err(e.into()),\n}","preventionTips":["Cancel only from explicit user actions, with UI feedback","Set a session-expiry timeout instead of relying on cancel alone for idle sessions","Track session status ('waiting_for_receiver') so a cancel knows the current phase"],"tags":["p2p","cancellation","sender","async"],"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"}