astrid-runtime/astrid · error

invalid FUSE callback token

Error message

invalid FUSE callback token

What it means

The mount lease's `lease_token` doubles as the callback authentication token and must be 16–4096 bytes with no control characters. A token that is absent, too short/long, or contains control characters is rejected before the FUSE service accepts the lease.

Source

Thrown at crates/astrid-storage-provider-fuse/src/service.rs:209

    }
    if let Some(identity) = parent.start_identity.as_deref()
        && (identity.is_empty() || identity.len() > 512 || identity.chars().any(char::is_control))
    {
        bail!("invalid FUSE service parent start identity");
    }
    #[cfg(target_os = "linux")]
    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")?;

View on GitHub (pinned to affd8760f4)

Solutions

  1. Regenerate the lease so `lease_token` is a fresh CSPRNG value of ≥16 bytes.
  2. Strip control characters (trim whitespace/newlines) when loading the token from storage or env.
  3. Check the lease broker/issuer version and fix token generation at the source.
  4. Validate the token length before writing lease.json so bad leases never reach the helper.

Example fix

// before
lease_token: short_id(), // e.g. 8 chars
// after
lease_token: generate_token(32), // 32 random bytes, hex-encoded, trimmed
Defensive patterns

Strategy: validation

Validate before calling

fn valid_lease_token(t: &str) -> bool {
    (16..=4096).contains(&t.len()) && !t.chars().any(char::is_control)
}

Type guard

fn has_valid_lease_token(lease: &StorageMountLeaseV1) -> bool {
    (16..=4096).contains(&lease.lease_token.len()) && !lease.lease_token.chars().any(char::is_control)
}

Prevention

When it happens

Trigger: `validate_lease` (called from `validate_launch`) finds `lease.lease_token.len() < 16 || > 4096 || contains control chars`.

Common situations: Lease issued by an older/buggy broker with a short token; token read from a file with trailing newline; truncated token in a serialized lease; hand-crafted lease JSON in tests.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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