astrid-runtime/astrid · error

detached FUSE service returned an incompatible readiness res

Error message

detached FUSE service returned an incompatible readiness response

What it means

This error means the detached FUSE service answered its readiness probe with `ControlResponse::Done`, which is not a valid readiness response. Readiness requires a `Status` carrying the served access; `Done` signals the service is terminating or speaking an incompatible protocol shape. It is thrown from the readiness validation helper in main.rs:346.

Source

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

            )
        },
    )
}

fn require_ready_control_response(
    response: ControlResponse,
    expected_access: StorageProviderAccessV1,
) -> Result<()> {
    match response {
        ControlResponse::Status { access } if access == expected_access => Ok(()),
        ControlResponse::Status { access } => {
            bail!("detached FUSE service readiness access {access:?} does not match its lease")
        },
        ControlResponse::Failure { code, message } => {
            bail!("detached FUSE service readiness failed [{code}]: {message}")
        },
        ControlResponse::Done => {
            bail!("detached FUSE service returned an incompatible readiness response")
        },
    }
}

async fn sync(
    client: &mut AdminClient,
    acting_principal: &astrid_core::PrincipalId,
    selector: &StorageMountSelectorV1,
) -> Result<StorageProviderSuccessV1> {
    let record = registry::resolve_record(selector)?;
    let status = require_live_lease(client, acting_principal, &record).await?;
    validate_record(&record, &status)?;
    let control = live_control_status(client, acting_principal, &record).await?;
    match control {
        ControlResponse::Status { access } if access == record.access => {},
        ControlResponse::Status { access } => {
            bail!("detached FUSE service access {access:?} does not match lease")
        },

View on GitHub (pinned to affd8760f4)

Solutions

  1. Check whether the detached service process is still alive and inspect its logs for early exit.
  2. Clean up stale artifacts (control socket, mountpoint) and restart the service from the current lease.
  3. Align client/service crate versions so ControlResponse variants mean the same thing on both sides.
  4. Retry readiness with a short backoff in case the probe raced service startup shutdown logic.
Defensive patterns

Strategy: try-catch

Type guard

fn is_ready_status(resp: &ControlResponse) -> bool {
    matches!(resp, ControlResponse::Status { .. })
}

Try / catch

match validate_readiness(resp, &lease.access) {
    Err(e) if e.to_string().contains("incompatible readiness response") => {
        // check service liveness, restart with backoff
    }
    r => r?,
}

Prevention

When it happens

Trigger: The readiness check matches `ControlResponse::Done` — e.g. the service shut down immediately after start, or a different/newer control protocol maps the reply onto the Done variant.

Common situations: The detached service crashed or exited before becoming ready; the control socket was answered by a stale or foreign process; client and service crate versions disagree on response semantics.

Related errors


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