astrid-runtime/astrid · error

detached FUSE stderr sink handoff timed out

Error message

detached FUSE stderr sink handoff timed out

What it means

The parent process waits on a timeout for the detached FUSE child's stderr drain task to complete the sink handoff. If the child does not signal readiness (or fail) within the timeout window, the parent aborts the drain task, kills the child, records its exit status, and returns this timeout error.

Solutions

  1. Check the child's exit status in the error context to see if it was still alive when killed
  2. Verify /dev/fuse exists and the fuse kernel module is loaded
  3. Clean up stale FUSE registry entries and locks from prior crashed mounts
  4. Increase the handoff timeout if the environment is slow (containers, cold storage)
  5. Run the FUSE daemon in the foreground to observe where it hangs

Example fix

// before
Err(anyhow::anyhow!("detached FUSE stderr sink handoff timed out"))
// after: include elapsed time and child status for diagnosis
Err(anyhow::anyhow!("detached FUSE stderr sink handoff timed out after {timeout:?}")
    .context(format!("detached FUSE service status: {status:?}")))
Defensive patterns

Strategy: retry

Validate before calling

// pre-check daemon prerequisites
assert!(Path::new("/dev/fuse").exists(), "fuse device missing");
assert!(!is_already_mounted(&mountpoint), "stale mountpoint");

Try / catch

match result {
    Err(e) if e.to_string().contains("timed out") => {
        cleanup_stale_registry();
        retry_with_longer_timeout();
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: The detached FUSE daemon starts but never completes its startup handshake within the timeout period — e.g. it hangs waiting on /dev/fuse, blocks on a stale mountpoint, or is stuck initializing.

Common situations: Stale mount.lock or leftover registry entry from a previous crash; /dev/fuse unavailable or fuse kernel module not loaded; very slow disk/container startup exceeding the fixed timeout; the daemon deadlocks before writing READY.

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


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

Appendix: source

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

                    .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:?}")))
                },
            }
        },
        Err(error) => {
            let _ = child.kill().await;
            let status = child.wait().await;
            let stderr = match stderr_task.await {
                Ok(Ok(bytes)) => bounded_stderr_snippet(&bytes),
                Ok(Err(_)) | Err(_) => String::new(),
            };
            let status_context = format!("detached FUSE service status: {status:?}");
            if stderr.is_empty() {
                Err(error.context(status_context))
            } else {
                Err(error.context(format!("{status_context}; stderr: {stderr}")))
            }
        },

View on GitHub (pinned to affd8760f4)