{"record":{"id":"837e2b729e6bb7ce","repo":"tonhowtf/omniget","slug":"unexpected-relay-response-mod","errorCode":null,"errorMessage":"Unexpected relay response: {}","messagePattern":"Unexpected relay response: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-tauri/src/platforms/p2p/mod.rs","lineNumber":135,"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":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/src/platforms/p2p/mod.rs#L117-L153","documentation":"download() reads a line from the relay server after connecting and expects exactly \"READY\"; check_relay_error already filtered explicit relay error lines. Any other line means the relay/sender protocol is out of sync (or an empty/garbage line arrived), so download aborts with this message echoing the raw response.","triggerScenarios":"Relay replies with a line other than \"READY\" after check_relay_error passes — e.g. an empty line from a closed relay connection, a protocol version mismatch, or the sender never completed handshake so the relay sent something else.","commonSituations":"Relay server version differs from the client (old relay sends \"OK\" or blank), sender dropped out between connection and READY, or a proxy/load balancer injected an HTTP error page as a line.","solutions":["Verify the relay server version matches the client's relay protocol (READY handshake).","Log the raw response and check for an empty line — usually means the relay socket closed; retry the connection.","Check check_relay_error's recognized error lines; extend it if the relay has new error strings so they surface as real errors instead of this generic bail.","Retry the download; transient relay state can produce a premature non-READY line."],"exampleFix":"// before\nlet response = read_line(&mut reader).await?;\ncheck_relay_error(&response)?;\nif response != \"READY\" { anyhow::bail!(\"Unexpected relay response: {}\", response); }\n// after\nlet response = read_line(&mut reader).await?;\nif response.trim().is_empty() {\n    anyhow::bail!(\"Relay closed connection before READY; retrying\");\n}\ncheck_relay_error(&response)?;\nif response != \"READY\" { anyhow::bail!(\"Unexpected relay response: {:?}\", response); }","handlingStrategy":"retry","validationCode":"let md = tokio::fs::metadata(&output_path).await?; // ensure output dir writable before connecting\nif !output_dir_is_writable { anyhow::bail!(\"Output directory not writable\"); }","typeGuard":null,"tryCatchPattern":"match download(opts).await {\n    Err(e) if e.to_string().contains(\"Unexpected relay response\") => {\n        log::warn!(\"relay desync: {e}; retrying once\");\n        download(opts).await?; // retry with fresh connection\n    }\n    other => other?,\n}","preventionTips":["Keep relay server and client protocol versions in lockstep.","Log raw relay lines with {:?} in development to catch desyncs early.","Add a read timeout around read_line so a dead relay fails fast instead of returning empty lines.","Extend check_relay_error whenever the relay adds new error strings."],"tags":["network","p2p","protocol-mismatch","relay"],"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"}