{"record":{"id":"861381946709e61a","repo":"astrid-runtime/astrid","slug":"inspect-detached-fuse-service-after-stderr-sink-ha","errorCode":null,"errorMessage":"inspect detached FUSE service after stderr sink handoff","messagePattern":"inspect detached FUSE service after stderr sink handoff","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/astrid-storage-provider-fuse/src/main.rs","lineNumber":668,"sourceCode":"            if stderr.is_empty() {\n                Err(error.context(status_context))\n            } else {\n                Err(error.context(format!(\"{status_context}; stderr: {stderr}\")))\n            }\n        },\n    }\n}\n\nasync fn require_service_running_after_handoff(\n    child: &mut tokio::process::Child,\n) -> Result<()> {\n    match child.try_wait() {\n        Ok(None) => Ok(()),\n        Ok(Some(status)) => bail!(\"detached FUSE service exited after readiness: {status}\"),\n        Err(error) => {\n            let _ = child.kill().await;\n            let status = child.wait().await;\n            Err(anyhow::Error::new(error)\n                .context(\"inspect detached FUSE service after stderr sink handoff\")\n                .context(format!(\"detached FUSE service status: {status:?}\")))\n        },\n    }\n}\n\nasync fn read_service_startup(\n    child: &mut tokio::process::Child,\n    launch: &ServiceLaunch,\n    control_path: &Path,\n) -> Result<ControlReady> {\n    let mut stdin = child\n        .stdin\n        .take()\n        .context(\"FUSE service stdin is unavailable\")?;\n    let bytes = serde_json::to_vec(launch)?;\n    stdin.write_all(&bytes).await?;\n    stdin.write_all(b\"\\n\").await?;","sourceCodeStart":650,"sourceCodeEnd":686,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-storage-provider-fuse/src/main.rs#L650-L686","documentation":"After the stderr sink handoff, require_service_running_after_handoff polls the detached FUSE child with try_wait. If the child has already exited, it bails with the exit status, kills/waits as needed, and wraps any try_wait error with this context plus the final status.","triggerScenarios":"try_wait returns Err(error) while verifying the detached FUSE service is still alive after readiness — the child handle is invalid or the OS reports a wait error; Ok(Some(status)) takes the separate bail! path with the exit status.","commonSituations":"The FUSE service exits immediately after reporting readiness (bad mount options, permission denied on the mountpoint); the child process handle became invalid; PID reaping races in the supervisor.","solutions":["Fix the detached service so it stays running after readiness — check the reported exit status for the root cause","Validate FUSE mount options and mountpoint permissions before spawning the detached service","Ensure nothing else reaps the child PID (double wait) so try_wait does not error","Add a startup health/liveness check so a fast-exiting service is caught before handoff"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// verify the service stays up for a settle window after readiness\nfor _ in 0..10 {\n    if Path::new(&pid_file).exists() { break; }\n    tokio::time::sleep(Duration::from_millis(100)).await;\n}\nassert!(Path::new(&pid_file).exists(), \"FUSE service exited right after readiness\");","typeGuard":null,"tryCatchPattern":"match result {\n    Err(err) if err.to_string().contains(\"inspect detached FUSE service after stderr sink handoff\") => {\n        eprintln!(\"detached FUSE service exited/unstable after readiness: {err:#}\");\n        // retry spawn with backoff, then give up\n    }\n    other => other?,\n}","preventionTips":["Validate FUSE mount options and permissions before detaching the service","Wait for a liveness confirmation (pid file/mount visible) before considering startup done","Avoid double-reaping the child so try_wait is not called on an invalid handle"],"tags":["process","fuse","liveness","spawn"],"backgroundTag":"child-process-exited-unexpectedly","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}