astrid-runtime/astrid · error

mount rollback left the lease registered for recovery; {}

Error message

mount rollback left the lease registered for recovery; {}

What it means

During rollback after a failed mount, rollback_after_native_failure could not unmount the native filesystem (native_unmounted == false), so the storage-mount lease remains registered in the kernel and only background recovery can clean it up. The bail reports the accumulated step errors (unmount/inspect) joined with '; '.

Source

Thrown at crates/astrid-storage-provider-fskit/src/main.rs:340

async fn revoke_after_registry_failure(client: &mut AdminClient, mount_id: StorageMountId) {
    let _ = client
        .request(AdminRequestKind::StorageMountRevoke { mount_id })
        .await;
}

fn with_native_rollback(
    error: anyhow::Error,
    rollback: Result<()>,
) -> Result<StorageProviderSuccessV1> {
    match rollback {
        Ok(()) => Err(error),
        Err(rollback) => Err(error).context(rollback),
    }
}

fn rollback_outcome(native_unmounted: bool, errors: &[String]) -> Result<()> {
    if !native_unmounted {
        bail!(
            "mount rollback left the lease registered for recovery; {}",
            errors.join("; ")
        );
    }
    if errors.is_empty() {
        return Ok(());
    }
    bail!("mount rollback incomplete: {}", errors.join("; "))
}

async fn rollback_after_native_failure(
    client: &mut AdminClient,
    mount_id: &StorageMountId,
    mountpoint: &Path,
    auto_created: bool,
    native_mount_command_succeeded: bool,
) -> Result<()> {
    let mut errors = Vec::new();

View on GitHub (pinned to affd8760f4)

Solutions

  1. Free the mount: close processes holding files under the mountpoint, then unmount manually (e.g. diskutil unmount on macOS).
  2. Check native_mount_is_active for the path; if still mounted, retry unmount until it succeeds, then revoke the lease via StorageMountRevoke.
  3. Let kernel-side lease recovery expire the stale lease if manual unmount is impossible, then clean the registry entry.
  4. Re-run the mount operation afterwards; stale recovery on next unmount will handle leftover leases if authorize_stale_cleanup permits it.
Defensive patterns

Strategy: try-catch

Validate before calling

// before mounting, ensure no process holds the mountpoint
let busy = std::process::Command::new("lsof").arg(&mountpoint).status().map(|s| s.success()).unwrap_or(false);
if busy { return Err(anyhow!("mountpoint is busy; aborting mount")); }

Try / catch

match rollback_after_native_failure(&mut client, &mount_id, &mountpoint, auto_created, mounted).await {
    Err(e) if e.to_string().contains("left the lease registered for recovery") => {
        // retry native unmount after releasing busy resources, then revoke lease explicitly
    },
    other => { /* proceed */ },
}

Prevention

When it happens

Trigger: rollback_after_native_failure() runs after a mount attempt fails partway; native_unmount(mountpoint) or native_mount_is_active(mountpoint) errors out (e.g. fskit process crashed, mount is busy, macOS refuses detach), so rollback_outcome(false, errors) bails.

Common situations: A file under the mount is open by another process, making unmount return EBUSY; fskit daemon died so the native mount is in an unknown state; unmount tooling unavailable mid-rollback.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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