astrid-runtime/astrid · error
WinFsp daemon did not report readiness within 30 seconds
Error message
WinFsp daemon did not report readiness within 30 seconds
What it means
spawn_daemon wraps the readiness handshake in tokio::time::timeout(DAEMON_READY_TIMEOUT) of 30 seconds. If the daemon never prints a valid READY line within that window, it is killed and this error is raised, preventing indefinite hangs on a wedged daemon.
Source
Thrown at crates/astrid-storage-provider-winfsp/src/win.rs:596
bail!("WinFsp daemon returned invalid readiness: {ready:?}");
}
if child.try_wait().context("inspect WinFsp daemon")?.is_some() {
bail!("WinFsp daemon exited immediately after readiness");
}
Result::<()>::Ok(())
};
match tokio::time::timeout(DAEMON_READY_TIMEOUT, success).await {
Ok(Ok(())) => Ok(()),
Ok(Err(error)) => {
let _ = child.kill().await;
let _ = child.wait().await;
Err(error.context("start WinFsp native filesystem"))
},
Err(_) => {
let _ = child.kill().await;
let _ = child.wait().await;
bail!("WinFsp daemon did not report readiness within 30 seconds");
},
}
}
fn native_mountpoint(mountpoint: &Path) -> Result<PathBuf> {
let text = mountpoint
.to_str()
.context("WinFsp mountpoint is not valid Unicode")?;
let bytes = text.as_bytes();
if bytes.len() == 3
&& bytes[0].is_ascii_alphabetic()
&& bytes[1] == b':'
&& matches!(bytes[2], b'\\' | b'/')
{
// FspFileSystemSetMountPoint accepts drive designators (`X:`), not
// drive-root paths (`X:\\`). Keep the latter in the public lifecycle
// record while passing the native spelling to WinFsp.
return Ok(PathBuf::from(&text[..2]));View on GitHub (pinned to affd8760f4)
Solutions
- Check the daemon's stderr/log output during the 30s window to find where startup blocks.
- Fix stdout flushing in the daemon (use println! + flush or LineWriter) so READY is emitted promptly.
- Pre-install/warm the WinFsp driver so first-start initialization fits the timeout.
- Verify the launched command and arguments are correct and the binary doesn't wait on stdin.
Example fix
// before (daemon)
write!(stdout, "READY {}", mount_id)?; // buffered, never flushed
// after
let mut stdout = io::stdout();
writeln!(stdout, "READY {}", mount_id)?;
stdout.flush()?; Defensive patterns
Strategy: retry
Try / catch
match spawn_daemon(&lease, &launch).await {
Err(e) if e.to_string().contains("did not report readiness within 30 seconds") => {
// daemon was killed; inspect its stderr log, then retry after fixing startup stall
Err(e)
},
other => other,
} Prevention
- Flush stdout immediately after writing the READY line.
- Pre-warm/install the WinFsp driver before launch to avoid slow first init.
- Ensure the daemon never blocks on stdin or interactive prompts at startup.
- Alert on startup duration; if init legitimately exceeds 30s, negotiate a longer timeout upstream.
When it happens
Trigger: The spawned daemon produces no READY line within 30s: it blocks on driver loading, waits on a missing dependency, deadlocks during init, or stdout is not flushed.
Common situations: Slow WinFsp driver installation first-run; daemon blocked on a prompt or network call at startup; stdout buffering so READY exists but is never flushed; the wrong executable launched (e.g. a shell script that waits for input).
Understand the failure class
Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.
Related errors
- Daemon is still starting after {timeout_secs} seconds; it wa
- candidate generation for '{id}' exited before signaling read
- detached FUSE service failed: {message}
- timed out waiting for capsule command result
- editor '{editor}' exited with non-zero status
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/c1fff2d86d377271.
Report an issue: GitHub.