{"record":{"id":"8ab7939da15d539d","repo":"tonhowtf/omniget","slug":"unexpected-relay-response","errorCode":null,"errorMessage":"Unexpected relay response: {}","messagePattern":"Unexpected relay response: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-tauri/omniget-core/src/platforms/p2p.rs","lineNumber":133,"sourceCode":"            .ok_or_else(|| anyhow!(\"Invalid P2P URL\"))?;\n\n        let _ = progress.send(ProgressUpdate::percent(-2.0)).await;\n\n        tracing::info!(\"[p2p] connecting to relay for code: {}\", code);\n\n        let stream = connect_relay().await?;\n        let (read_half, mut write_half) = tokio::io::split(stream);\n        let mut reader = BufReader::new(read_half);\n\n        write_half\n            .write_all(format!(\"RECV {}\\n\", 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 != \"READY\" {\n            anyhow::bail!(\"Unexpected relay response: {}\", response);\n        }\n\n        tracing::info!(\"[p2p] connected to sender via relay\");\n\n        let file_name = read_line(&mut reader).await?;\n        let file_size_str = read_line(&mut reader).await?;\n        let file_size: u64 = file_size_str\n            .parse()\n            .map_err(|_| anyhow!(\"Invalid file size from sender: {}\", file_size_str))?;\n\n        tracing::info!(\"[p2p] receiving: {} ({} bytes)\", file_name, file_size);\n\n        write_half.write_all(b\"OK\\n\").await?;\n        write_half.flush().await?;\n\n        let _ = progress.send(ProgressUpdate::percent(0.0)).await;\n\n        let sanitized = sanitize_filename::sanitize(&file_name);","sourceCodeStart":115,"sourceCodeEnd":151,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/platforms/p2p.rs#L115-L151","documentation":"After the receiver connects through the relay, it reads one line and expects exactly \"READY\"; anything else means the relay/sender is not in the expected state. check_relay_error() runs first, so this fires only for non-error responses that are not READY — a protocol desynchronization between relay versions or a corrupted/short response.","triggerScenarios":"Calling download() and reaching the relay handshake where the relay responds with a line other than \"READY\" after check_relay_error passes — e.g. an unexpected \"WAIT\", empty line, or a mismatched relay protocol version.","commonSituations":"Receiver connecting before the sender finished registration; relay server version older/newer than the client expects; network proxy mangling the handshake line; stale relay code reused after the session ended.","solutions":["Verify the relay server protocol matches the client (both expect sender->WAIT, receiver->READY)","Re-generate the P2P code and retry — stale/expired codes cause off-protocol responses","Log the raw response line and add handling for known alternate states (e.g. retry on \"WAIT\" with backoff)"],"exampleFix":"// before\nif response != \"READY\" {\n    anyhow::bail!(\"Unexpected relay response: {}\", response);\n}\n// after\nmatch response.as_str() {\n    \"READY\" => {}\n    \"WAIT\" => anyhow::bail!(\"Sender not ready yet; retry the connection\"),\n    other => anyhow::bail!(\"Unexpected relay response: {}\", other),\n}","handlingStrategy":"retry","validationCode":"// Pre-flight: confirm the relay is reachable and protocol-compatible\nlet probe = tokio::net::TcpStream::connect(&relay_addr).await;\nif probe.is_err() { anyhow::bail!(\"Relay unreachable: {}\", relay_addr); }","typeGuard":null,"tryCatchPattern":"match p2p::download(&info, &opts, tx).await {\n    Err(e) if e.to_string().contains(\"Unexpected relay response\") => {\n        tracing::warn!(\"relay handshake mismatch, regenerating code and retrying\");\n        // regenerate code, retry once\n    }\n    other => other?,\n}","preventionTips":["Pin relay server and client versions together","Regenerate P2P codes per attempt; never reuse expired codes","Log raw handshake lines to diagnose protocol drift"],"tags":["p2p","relay","protocol","handshake"],"backgroundTag":"unexpected-response-shape","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"}