astrid-runtime/astrid · error

FSKit lease is expired

Error message

FSKit lease is expired

What it means

validate_lease compares the lease's expires_at_epoch_secs against the current system time and rejects leases that have already expired. Leases are short-lived credentials for FSKit mounts, so an expired lease is not accepted for launch.

Source

Thrown at crates/astrid-storage-provider-fskit/src/service.rs:151

    {
        bail!("FSKit service mountpoint overlaps the lease resource");
    }
    crate::validate_mountpoint_ancestors(&launch.mountpoint)?;
    crate::validate_unmounted_mountpoint(&launch.mountpoint)?;
    validate_control_path(&launch.control_path, &launch.lease.resource_path)?;
    Ok(())
}

fn validate_lease(lease: &astrid_core::storage_filesystem::StorageMountLeaseV1) -> Result<()> {
    if lease.lease_token.len() < 16 || lease.lease_token.len() > 4096 {
        bail!("FSKit lease callback token is invalid");
    }
    let now = SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .context("read system clock")?
        .as_secs();
    if lease.expires_at_epoch_secs < now {
        bail!("FSKit lease is expired");
    }
    if !lease.resource_path.is_absolute() || !lease.callback_path.is_absolute() {
        bail!("FSKit lease paths must be absolute");
    }
    #[cfg(target_os = "macos")]
    astrid_core::fskit_socket::validate_callback_path(lease.mount_id, &lease.callback_path)
        .map_err(anyhow::Error::msg)?;
    #[cfg(not(target_os = "macos"))]
    if lease.callback_path != lease.resource_path.join("control.sock") {
        bail!("FSKit callback path is not the kernel lease endpoint");
    }
    platform_fs::validate_private_directory(&lease.resource_path)
        .context("validate private FSKit lease resource")?;
    platform_fs::verify_no_redirects(&lease.resource_path)
        .context("reject redirected FSKit lease resource")?;
    platform_fs::validate_private_file(&lease.resource_path.join("lease.json"))
        .context("validate private FSKit lease manifest")?;
    let manifest = std::fs::read(lease.resource_path.join("lease.json"))

View on GitHub (pinned to affd8760f4)

Solutions

  1. Request a fresh lease from the kernel/provider and relaunch with it
  2. Fix system clock synchronization (NTP) if clock skew caused the false expiry
  3. Stop caching lease files across runs; read a newly issued lease each launch

Example fix

// before
let lease = std::fs::read("stale-lease.json")?; // expired
// after
let lease = request_fresh_lease()?; // expires_at_epoch_secs > now
Defensive patterns

Strategy: validation

Validate before calling

fn lease_live(lease: &StorageMountLeaseV1) -> bool {
    let now = std::time::SystemTime::now()
        .duration_since(std::time::UNIX_EPOCH).unwrap().as_secs();
    lease.expires_at_epoch_secs >= now
}

Try / catch

match provider.run(launch) {
    Err(e) if e.to_string().contains("lease is expired") => {
        let launch = refresh_lease(launch)?;
        provider.run(launch).await
    }
    r => r,
}

Prevention

When it happens

Trigger: validate_lease is called (via validate_launch or live_managed_callback_lease_is_accepted) with lease.expires_at_epoch_secs < now, e.g. a cached/replayed lease or a system clock set far in the future.

Common situations: Reusing a saved lease file after it expired; slow test runs replaying stale fixtures; machine clock skew (NTP drift or incorrect system clock making 'now' appear past expiry).

Related errors


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