tonhowtf/omniget · info
Send cancelled while waiting for receiver
Error message
Send cancelled while waiting for receiver
What it means
While the sender waits for the receiver's READY line, tokio::select! races read_line against cancel.cancelled(). If the CancellationToken fires first, run_sender bails with "Send cancelled while waiting for receiver". Expected cooperative cancellation, not a protocol failure.
Solutions
- No fix needed — handle it as expected cancellation in the caller and mark the session cancelled.
- If it fires unexpectedly, trace which component cancels the token (UI timeout, drop of session handle).
- Ensure the relay connection/socket is closed on cancellation so the receiver side doesn't hang.
Example fix
// before
run_sender(session).await?; // generic error surfaced to user
// after
if let Err(e) = run_sender(session).await {
if e.to_string().contains("Send cancelled") {
session.status.lock().await = "cancelled".into();
} else { return Err(e); }
} Defensive patterns
Strategy: try-catch
Validate before calling
if cancel.is_cancelled() { anyhow::bail!("Already cancelled before starting send"); } Try / catch
match run_sender(session.clone(), cancel.clone()).await {
Err(e) if e.to_string().contains("cancelled while waiting") => {
session.status.lock().await = "cancelled".into();
}
other => other?,
} Prevention
- Cancel only from explicit user action or a clearly-logged session timeout.
- Give each send session its own CancellationToken; never share across sessions.
- Update session status before cancelling so the UI state is consistent.
- Drop the session handle after cancelling to free the relay slot.
When it happens
Trigger: Calling cancel_token.cancel() on the send session while it is parked in the waiting_for_receiver state (after receiving WAIT from the relay, before READY arrives).
Common situations: User aborts a share before anyone enters the pairing code; the UI times out the session and cancels; app teardown cancels all sessions.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Send cancelled while waiting for OK
- Download cancelled
- Download cancelled
- Send cancelled during transfer
- Send cancelled while paused
AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12).
Data as JSON: /api/errors/e6841d4bdcfd6dac.
Report an issue: GitHub.
Appendix: source
Thrown at src-tauri/src/platforms/p2p/mod.rs:275
write_half
.write_all(format!("SEND {}\n", session.code).as_bytes())
.await?;
write_half.flush().await?;
let response = read_line(&mut reader).await?;
check_relay_error(&response)?;
if response != "WAIT" {
anyhow::bail!("Unexpected relay response: {}", response);
}
*session.status.lock().await = "waiting_for_receiver".to_string();
tracing::info!("[p2p] waiting for receiver... code: {}", session.code);
let ready = tokio::select! {
line = read_line(&mut reader) => line?,
_ = cancel.cancelled() => {
anyhow::bail!("Send cancelled while waiting for receiver");
}
};
check_relay_error(&ready)?;
if ready != "READY" {
anyhow::bail!("Unexpected relay response: {}", ready);
}
*session.status.lock().await = "connected".to_string();
tracing::info!("[p2p] receiver connected");
let header = format!("{}\n{}\n", session.file_name, session.file_size);
write_half.write_all(header.as_bytes()).await?;
write_half.flush().await?;
let ok_response = tokio::select! {
line = read_line(&mut reader) => line?,
_ = cancel.cancelled() => {View on GitHub (pinned to 8600b91f42)