{"record":{"id":"0dd2d232afa48551","repo":"astrid-runtime/astrid","slug":"winfsp-stop-timed-out","errorCode":null,"errorMessage":"WinFsp stop timed out","messagePattern":"WinFsp stop timed out","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-storage-provider-winfsp/src/win.rs","lineNumber":668,"sourceCode":"        };\n        stream\n            .write_all(b\"STOP\")\n            .await\n            .context(\"send WinFsp stop\")?;\n        stream.flush().await.context(\"flush WinFsp stop\")?;\n        let mut acknowledgement = [0_u8; 1];\n        stream\n            .read_exact(&mut acknowledgement)\n            .await\n            .context(\"read WinFsp stop acknowledgement\")?;\n        if acknowledgement[0] != b'S' {\n            bail!(\"WinFsp daemon returned an invalid stop acknowledgement\");\n        }\n        Result::<()>::Ok(())\n    };\n    tokio::time::timeout(DAEMON_STOP_TIMEOUT, stop)\n        .await\n        .map_err(|_| anyhow::anyhow!(\"WinFsp stop timed out\"))??;\n\n    let deadline = tokio::time::Instant::now()\n        .checked_add(DAEMON_STOP_TIMEOUT)\n        .ok_or_else(|| anyhow::anyhow!(\"WinFsp stop deadline overflow\"))?;\n    while endpoint_is_present(control_path) {\n        if tokio::time::Instant::now() >= deadline {\n            bail!(\"WinFsp control endpoint remained live after stop\");\n        }\n        tokio::time::sleep(Duration::from_millis(25)).await;\n    }\n    Ok(())\n}\n\nfn initialize_winfsp() -> Result<()> {\n    load_adjacent_winfsp().context(\"load co-installed WinFsp runtime\")?;\n    winfsp_wrs::init().context(\"initialize installed WinFsp runtime\")\n}\n","sourceCodeStart":650,"sourceCodeEnd":686,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-storage-provider-winfsp/src/win.rs#L650-L686","documentation":"Raised in `stop_daemon` (crates/astrid-storage-provider-winfsp/src/win.rs:668) when the asynchronous stop sequence — connecting to the daemon's control endpoint, sending `STOP`, and reading the single-byte acknowledgement — does not complete within `DAEMON_STOP_TIMEOUT`. The timeout wrapper converts the elapsed future into this error. It indicates the WinFsp daemon is hung, unreachable in a non-NotFound way, or its control channel is unresponsive.","triggerScenarios":"Specifically: `tokio::time::timeout(DAEMON_STOP_TIMEOUT, stop)` elapses. Cases: `local_transport::connect(control_path)` accepts but never completes, the `STOP` write never flushes, or the daemon never sends the `b'S'` acknowledgement byte before the deadline.","commonSituations":"The WinFsp daemon thread is blocked inside a filesystem callback and cannot service the control socket; the endpoint exists but the daemon process is wedged or being torn down by the OS; resource exhaustion (the daemon's runtime cannot make progress); a stale endpoint held by a dead process whose socket still accepts connections.","solutions":["Check whether the WinFsp service process is still running and inspect its logs for a stuck filesystem callback blocking the service loop.","Verify nothing else is holding the control endpoint connection open (a leaked client keeps the stop handshake from completing).","If the daemon is wedged, forcibly terminate the service process, then remove the leftover endpoint file before remounting.","Retry `stop_daemon` once the system is under lighter load; if timeouts recur, consider raising `DAEMON_STOP_TIMEOUT`.","Confirm the mountpoint was actually unmounted after force-kill to avoid the stale-mount state."],"exampleFix":"// before\ntokio::time::timeout(DAEMON_STOP_TIMEOUT, stop)\n    .await\n    .map_err(|_| anyhow::anyhow!(\"WinFsp stop timed out\"))??;\n// after (caller-side guard)\nmatch tokio::time::timeout(DAEMON_STOP_TIMEOUT, stop_daemon(&control_path)).await {\n    Ok(Ok(())) => {}\n    Ok(Err(e)) => warn!(error = %e, \"graceful stop failed; forcing teardown\"),\n    Err(_) => { warn!(\"WinFsp stop timed out; killing daemon\"); kill_daemon(&pid_path); }\n}","handlingStrategy":"retry","validationCode":"// Confirm the daemon is responsive before attempting a stop\nif !endpoint_is_present(control_path) {\n    return Ok(()); // already gone, no stop needed\n}","typeGuard":"fn daemon_stoppable(control_path: &Path) -> bool {\n    endpoint_is_present(control_path) && daemon_pid_is_alive(pid_path())\n}","tryCatchPattern":"match tokio::time::timeout(DAEMON_STOP_TIMEOUT, stop_daemon(&control_path)).await {\n    Ok(Ok(())) => info!(\"daemon stopped cleanly\"),\n    Ok(Err(e)) => { warn!(error = %e, \"stop failed; forcing teardown\"); force_teardown(); }\n    Err(_elapsed) => { warn!(\"WinFsp stop timed out; killing daemon\"); force_teardown(); }\n}","preventionTips":["Keep filesystem callbacks non-blocking so the service loop can always answer the control socket.","Detect and reap wedged daemon processes with a liveness watchdog.","After a timeout, always force-kill and clean the endpoint file before remounting.","Size DAEMON_STOP_TIMEOUT generously for heavily loaded hosts."],"tags":["winfsp","timeout","shutdown","windows","ipc"],"backgroundTag":"request-timeout","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}