astrid-runtime/astrid · critical

detached FUSE service returned a mismatched lease identity

Error message

detached FUSE service returned a mismatched lease identity

What it means

After launching the detached FUSE service, the parent reads the service's Ready reply and verifies that the mount_id and access mode match the StorageMountLeaseV1 it granted. A mismatch means the reply did not correspond to this launch — a protocol or identity corruption — so the mount is rolled back via rollback_mount_error. This protects against mounting with the wrong lease (wrong tenant or access level).

Source

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

        })
        .await?;
    let lease = lease_from_response(body)?;
    let control_path = registry::control_path(&lease.mount_id)?;
    let launch = ServiceLaunch {
        lease: lease.clone(),
        requested_by: acting_principal,
        mountpoint: mountpoint.clone(),
        auto_created_mountpoint: auto_created,
    };
    let startup = launch_service(&launch, &control_path).await;
    let ready = match startup {
        Ok(ready) => ready,
        Err(error) => {
            return Err(rollback_mount_error(error, client, &launch, &control_path).await);
        },
    };
    if ready.mount_id != lease.mount_id || ready.access != lease.access {
        let error = anyhow::anyhow!("detached FUSE service returned a mismatched lease identity");
        return Err(rollback_mount_error(error, client, &launch, &control_path).await);
    }
    if ready.pid == 0 {
        let error = anyhow::anyhow!("detached FUSE service returned an invalid process identity");
        return Err(rollback_mount_error(error, client, &launch, &control_path).await);
    }
    let control_ready = call_control(
        &control_path,
        &ControlRequest::Status {
            requested_by: launch.requested_by.clone(),
        },
    )
    .and_then(|response| require_ready_control_response(response, lease.access));
    if let Err(error) = control_ready {
        let error = error.context("detached FUSE service failed its readiness handshake");
        return Err(rollback_mount_error(error, client, &launch, &control_path).await);
    }
    let record = registry::MountRecord {

View on GitHub (pinned to affd8760f4)

Solutions

  1. Ensure each detached launch uses a unique, freshly created launch/control path per mount.
  2. Kill and remove stale service processes and sockets from prior runs before remounting.
  3. Align host and provider binary versions so the Ready payload schema matches.
  4. Retry the mount after cleanup; the rollback has already released the bad mount.

Example fix

// before
let control_path = std::env::temp_dir().join("astrid-fuse-control");
// after
let control_path = std::env::temp_dir().join(format!("astrid-fuse-control-{}", uuid::Uuid::new_v4()));
Defensive patterns

Strategy: validation

Validate before calling

fn ready_matches(ready: &Ready, lease: &StorageMountLeaseV1) -> bool {
    ready.mount_id == lease.mount_id && ready.access == lease.access
}

Type guard

fn is_valid_ready(ready: &Ready, lease: &StorageMountLeaseV1) -> bool {
    ready.mount_id == lease.mount_id
        && ready.access == lease.access
        && ready.pid != 0
}

Try / catch

if ready.mount_id != lease.mount_id || ready.access != lease.access {
    let error = anyhow::anyhow!("detached FUSE service returned a mismatched lease identity");
    return Err(rollback_mount_error(error, client, &launch, &control_path).await);
}

Prevention

When it happens

Trigger: call_launch -> detached service responds with Ready whose mount_id != lease.mount_id or access != lease.access; caused by stale control sockets, a reused launch file, or a service binary at a different version replying with foreign identity data.

Common situations: Concurrent mounts overwriting each other's launch/control paths in a shared temp dir; stale sockets from a previous crashed run; version skew between host and provider binary.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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