{"record":{"id":"a3472299ab38dd5e","repo":"astrid-runtime/astrid","slug":"winfsp-daemon-returned-invalid-readiness-ready","errorCode":null,"errorMessage":"WinFsp daemon returned invalid readiness: {ready:?}","messagePattern":"WinFsp daemon returned invalid readiness: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-storage-provider-winfsp/src/win.rs","lineNumber":578,"sourceCode":"        stdin\n            .write_all(b\"\\n\")\n            .await\n            .context(\"terminate daemon lease\")?;\n        drop(stdin);\n\n        let stdout = child\n            .stdout\n            .take()\n            .context(\"WinFsp daemon stdout is unavailable\")?;\n        let mut stdout = tokio::io::BufReader::new(stdout);\n        let mut ready = String::new();\n        stdout\n            .read_line(&mut ready)\n            .await\n            .context(\"read WinFsp daemon readiness\")?;\n        let expected = format!(\"READY {}\\n\", lease.mount_id);\n        if ready != expected {\n            bail!(\"WinFsp daemon returned invalid readiness: {ready:?}\");\n        }\n        if child.try_wait().context(\"inspect WinFsp daemon\")?.is_some() {\n            bail!(\"WinFsp daemon exited immediately after readiness\");\n        }\n        Result::<()>::Ok(())\n    };\n\n    match tokio::time::timeout(DAEMON_READY_TIMEOUT, success).await {\n        Ok(Ok(())) => Ok(()),\n        Ok(Err(error)) => {\n            let _ = child.kill().await;\n            let _ = child.wait().await;\n            Err(error.context(\"start WinFsp native filesystem\"))\n        },\n        Err(_) => {\n            let _ = child.kill().await;\n            let _ = child.wait().await;\n            bail!(\"WinFsp daemon did not report readiness within 30 seconds\");","sourceCodeStart":560,"sourceCodeEnd":596,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-storage-provider-winfsp/src/win.rs#L560-L596","documentation":"spawn_daemon waits for the daemon's stdout readiness line, which must be exactly \"READY {mount_id}\\n\". Any other line (different text, different mount id, extra whitespace, or a wrapped error message) is rejected, ensuring the daemon is alive, is the right mount, and follows the handshake contract.","triggerScenarios":"spawn_daemon reads the first stdout line and it does not equal format!(\"READY {}\\n\", lease.mount_id): wrong mount_id passed to the daemon, daemon prints banner/diagnostics before READY, \\r\\n line endings on Windows, or a panic message on stdout.","commonSituations":"The daemon binary on PATH is a different/older version without the READY handshake; launch arguments transposed so the daemon receives another mount id; stdout redirected through a wrapper that adds prefixes; Windows CRLF line endings.","solutions":["Run the daemon with the correct mount_id argument matching lease.mount_id.","Strip banner/diagnostic output (send logging to stderr) so READY is the first stdout line.","Check for CRLF: the daemon must emit \"READY {id}\\n\", not \"\\r\\n\"; fix eprintln/print usage.","Verify the daemon executable version matches the library's handshake protocol."],"exampleFix":"// before (daemon)\nprintln!(\"READY {}\\r\\n\", mount_id); // CRLF mismatch\n// after\nprintln!(\"READY {}\", mount_id);","handlingStrategy":"try-catch","validationCode":"let expected = format!(\"READY {}\\n\", lease.mount_id);\n// after reading the line: assert_eq!(ready, expected);","typeGuard":"fn is_valid_ready_line(line: &str, mount_id: &str) -> bool {\n    line == format!(\"READY {mount_id}\\n\")\n}","tryCatchPattern":"match spawn_daemon(&lease, &launch).await {\n    Err(e) if e.to_string().contains(\"invalid readiness\") => {\n        // inspect daemon stderr, verify binary version and mount_id argument\n        Err(e)\n    },\n    other => other,\n}","preventionTips":["Pass the daemon its mount_id exactly as held in the lease.","Route all daemon logging to stderr so READY is the first stdout line.","Emit \"\\n\" (LF) line endings only, even on Windows.","Pin the daemon binary version to match the library handshake."],"tags":["handshake","ipc","process"],"backgroundTag":"unexpected-response-shape","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}