astrid-runtime/astrid · error

read detached FUSE stderr during sink handoff

Error message

read detached FUSE stderr during sink handoff

What it means

When spawning the detached FUSE service, a handoff task reads the child's stderr through a sink after detachment. If that task returns an error, main kills the child, waits for its exit status, and wraps the error with this context plus the child's exit status for diagnostics.

Solutions

  1. Read the detached FUSE service status printed in the error context and fix the underlying service startup failure first
  2. Check the FUSE provider logs/stderr captured by the sink for the root-cause panic or message
  3. Verify the FUSE mount point is available and the provider binary is runnable before spawning
  4. Re-run in the foreground (non-detached mode) to see the service's stderr directly
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-flight before spawning the detached FUSE service
assert!(Path::new(&fuse_binary).exists(), "FUSE provider binary missing");
assert!(Path::new(&mountpoint).exists(), "mountpoint missing");
let status = Command::new(&fuse_binary).arg("--version").status()?;
assert!(status.success(), "FUSE provider not runnable");

Try / catch

match result {
    Err(err) if err.to_string().contains("read detached FUSE stderr during sink handoff") => {
        eprintln!("FUSE service failed during startup handoff: {err:#}");
        eprintln!("re-run in foreground to capture stderr directly");
    }
    other => other?,
}

Prevention

When it happens

Trigger: The stderr-sink handoff future completes with Err — the detached FUSE service wrote/closed stderr abnormally or the sink task failed — while main was waiting on Ok(Ok(Err(error))) from the select/join of readiness and handoff futures.

Common situations: The FUSE service crashes during startup and emits a panic trace to stderr; stderr pipe is closed unexpectedly; handoff task itself errors while relaying stderr.

Related errors


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

Appendix: source

Thrown at crates/astrid-storage-provider-fuse/src/main.rs:623

            if read == 0 {
                break;
            }
            let remaining = (MAX_FUSE_STDERR_BYTES + 1).saturating_sub(bytes.len());
            bytes.extend_from_slice(&buffer[..read.min(remaining)]);
        }
        std::io::Result::Ok(bytes)
    });
    let startup = read_service_startup(&mut child, launch, control_path).await;
    match startup {
        Ok(ready) => {
            match tokio::time::timeout(Duration::from_secs(1), &mut stderr_task).await {
                Ok(Ok(Ok(_))) => require_service_running_after_handoff(&mut child)
                    .await
                    .map(|()| ready),
                Ok(Ok(Err(error))) => {
                    let _ = child.kill().await;
                    let status = child.wait().await;
                    Err(anyhow::Error::new(error)
                        .context("read detached FUSE stderr during sink handoff")
                        .context(format!("detached FUSE service status: {status:?}")))
                },
                Ok(Err(error)) => {
                    let _ = child.kill().await;
                    let status = child.wait().await;
                    Err(anyhow::anyhow!("detached FUSE stderr drain failed: {error}")
                        .context(format!("detached FUSE service status: {status:?}")))
                },
                Err(_) => {
                    stderr_task.abort();
                    let _ = child.kill().await;
                    let status = child.wait().await;
                    Err(anyhow::anyhow!("detached FUSE stderr sink handoff timed out")
                        .context(format!("detached FUSE service status: {status:?}")))
                },
            }
        },

View on GitHub (pinned to affd8760f4)