astrid-runtime/astrid · error

build WinFsp callback filesystem

Error message

build WinFsp callback filesystem: {failure:?}

What it means

In the WinFsp daemon entrypoint, CallbackFs::new constructs the filesystem callback object from the mount lease and tokio runtime. If construction fails, the debug representation of the failure is wrapped in this anyhow error and the daemon aborts before initializing WinFsp.

Solutions

  1. Inspect the {failure:?} payload in the message for the inner cause
  2. Validate the mount lease contents before spawning the daemon
  3. Ensure the daemon binary and caller are the same version (lease schema match)
  4. Regenerate the lease rather than reusing a stale one from the registry

Example fix

// before: only Debug of failure
.map_err(|failure| anyhow::anyhow!("build WinFsp callback filesystem: {failure:?}"))?;
// after: keep error chain
.map_err(|failure| anyhow::anyhow!("build WinFsp callback filesystem: {failure:?}"))
    .with_context(|| format!("mount_id: {}", lease.mount_id))?;
Defensive patterns

Strategy: validation

Validate before calling

// validate the lease fields CallbackFs depends on before spawning the daemon
if lease.mount_id.is_empty() || lease.access.is_none() {
    return Err("incomplete mount lease");
}

Try / catch

match result {
    Err(e) if e.to_string().contains("build WinFsp callback filesystem") => {
        // parse inner failure:? and regenerate the lease before retry
    }
    r => r,
}

Prevention

When it happens

Trigger: CallbackFs::new returns Err — e.g. the StorageMountLeaseV1 contains invalid or missing fields, runtime state cannot be captured, or lease validation inside CallbackFs fails.

Common situations: A malformed or partially populated mount lease handed to the daemon; version skew between the parent process and daemon binary producing incompatible lease formats; lease deserialized from a stale registry record.

Related errors


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/418f6cbb06dcbdad. Report an issue: GitHub.

Appendix: source

Thrown at crates/astrid-storage-provider-winfsp/src/win.rs:75

        bail!("WinFsp daemon lease exceeds limit");
    }
    let start: DaemonStart =
        serde_json::from_slice(&bytes).context("decode WinFsp daemon lease")?;
    let lease = start.lease;
    if (!start.mountpoint.is_absolute() && !is_drive_designator(&start.mountpoint))
        || !lease.callback_path.is_absolute()
    {
        bail!("WinFsp daemon lease contains a relative endpoint");
    }

    let runtime = Arc::new(
        tokio::runtime::Builder::new_multi_thread()
            .enable_all()
            .build()
            .context("start WinFsp callback runtime")?,
    );
    let callback = CallbackFs::new(lease.clone(), Arc::clone(&runtime))
        .map_err(|failure| anyhow::anyhow!("build WinFsp callback filesystem: {failure:?}"))?;
    let control_path = provider_control_path(&lease.mount_id)?;
    let control_listener = local_transport::bind(&control_path)
        .with_context(|| format!("bind WinFsp control endpoint {}", control_path.display()))?;
    initialize_winfsp()?;
    let mountpoint = U16CString::from_os_str(start.mountpoint.as_os_str())
        .map_err(|_| anyhow::anyhow!("mountpoint is not valid UTF-16"))?;
    let filesystem = FileSystem::start(volume_params(lease.access), Some(&mountpoint), callback)
        .map_err(|status| {
            anyhow::anyhow!("WinFsp failed to start mount with status {status:#x}")
        })?;
    wait_for_mountpoint_ready(&start.mountpoint)?;

    let mut stdout = std::io::stdout().lock();
    writeln!(stdout, "READY {0}", lease.mount_id).context("report WinFsp readiness")?;
    stdout.flush().context("flush WinFsp readiness")?;

    let result = runtime.block_on(daemon_loop(filesystem, control_listener));
    if let Err(error) = result {

View on GitHub (pinned to affd8760f4)