astrid-runtime/astrid · error
FUSE lease is expired
Error message
FUSE lease is expired
What it means
Every mount lease carries an expiry timestamp (`expires_at_epoch_secs`). Before starting the FUSE service, the helper compares it to the current UNIX time and refuses to mount with a lease that has already expired, ensuring stale grants cannot create mounts.
Source
Thrown at crates/astrid-storage-provider-fuse/src/service.rs:216
if parent.start_identity.is_none() {
bail!("FUSE service parent start identity is required on Linux");
}
Ok(())
}
fn validate_lease(lease: &StorageMountLeaseV1) -> Result<()> {
if lease.lease_token.len() < 16
|| lease.lease_token.len() > 4096
|| lease.lease_token.chars().any(char::is_control)
{
bail!("invalid FUSE callback token");
}
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.context("read system clock")?
.as_secs();
if lease.expires_at_epoch_secs < now {
bail!("FUSE lease is expired");
}
if !lease.resource_path.is_absolute() || !lease.callback_path.is_absolute() {
bail!("FUSE lease paths must be absolute");
}
if lease.callback_path != lease.resource_path.join("control.sock") {
bail!("FUSE callback path is not the kernel lease endpoint");
}
platform_fs::validate_private_directory(&lease.resource_path)
.context("validate private FUSE lease resource")?;
platform_fs::verify_no_redirects(&lease.resource_path)
.context("reject redirected FUSE lease resource")?;
let manifest_path = lease.resource_path.join("lease.json");
platform_fs::validate_private_file(&manifest_path)
.context("validate private FUSE lease manifest")?;
let manifest = std::fs::read(&manifest_path).context("read FUSE lease manifest")?;
if manifest.len() > 64 * 1024 {
bail!("FUSE lease manifest exceeds the bounded size");
}View on GitHub (pinned to affd8760f4)
Solutions
- Request a fresh lease from the broker and retry the mount.
- Fix system clock (NTP sync) if skew or resume drift caused the mismatch.
- Re-issue the lease with a longer TTL for slow/unreliable startup paths.
- Check that the expiry epoch is computed in seconds (not millis) when the lease is created.
- Don't cache lease.json across runs — reload it at mount time.
Example fix
// before expires_at_epoch_secs: now + 60, // expires during slow startup // after expires_at_epoch_secs: now + 3600, // longer TTL // or: refresh the lease before mounting let lease = broker.refresh_lease(&mount_id).await?;
Defensive patterns
Strategy: validation
Validate before calling
let now = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH)?.as_secs();
if lease.expires_at_epoch_secs < now + 60 {
lease = broker.refresh_lease(&lease).await?; // refresh if near expiry
} Type guard
fn lease_is_current(lease: &StorageMountLeaseV1) -> bool {
let now = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).map(|d| d.as_secs()).unwrap_or(0);
lease.expires_at_epoch_secs >= now
} Try / catch
match mount(&lease).await {
Err(e) if e.to_string().contains("lease is expired") => {
let fresh = broker.refresh_lease(&lease).await?;
mount(&fresh).await
}
other => other,
} Prevention
- Refresh the lease before mounting instead of reusing cached lease.json
- Enable NTP time sync to avoid clock skew
- Issue leases with TTL large enough for slow startup
- Verify expiry is in epoch seconds, not milliseconds
When it happens
Trigger: `validate_lease` computes `now` from `SystemTime::now()` and finds `lease.expires_at_epoch_secs < now` during `validate_launch`.
Common situations: Clock skew between the machine issuing the lease and the machine mounting (VM/container clock drift); a cached lease.json reused after its TTL; suspended/resumed laptop with a short-lived lease; lease generated with a wrong (past) expiry.
Related errors
- FSKit lease is expired
- WinFsp lease is expired
- detached FUSE service readiness access {access:?} does not m
- detached FUSE service access {access:?} does not match lease
- registered FUSE service access {access:?} does not match its
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/092f8cda66211b92.
Report an issue: GitHub.