astrid-runtime/astrid · error

WinFsp lease manifest exceeds the bounded size

Error message

WinFsp lease manifest exceeds the bounded size

What it means

Before trusting a launch, the service reads lease.json from the lease resource directory and enforces a hard cap of 64 KiB on the manifest. A larger file is rejected because lease manifests are small structured documents; anything bigger indicates corruption, accidental embedding of payload data, or a tampering attempt (bloat to exhaust parser resources).

Source

Thrown at crates/astrid-storage-provider-winfsp/src/win.rs:283

    if lease.lease_token.len() < 16 || lease.lease_token.len() > 4096 {
        bail!("WinFsp lease callback token is invalid");
    }
    if !lease.resource_path.is_absolute()
        || !lease.callback_path.is_absolute()
        || lease.callback_path != lease.resource_path.join("control.endpoint")
    {
        bail!("WinFsp lease paths are malformed");
    }
    platform_fs::validate_private_directory(&lease.resource_path)
        .context("validate private WinFsp lease resource")?;
    platform_fs::verify_no_redirects(&lease.resource_path)
        .context("reject redirected WinFsp lease resource")?;
    let manifest_path = lease.resource_path.join("lease.json");
    platform_fs::validate_private_file(&manifest_path)
        .context("validate private WinFsp lease manifest")?;
    let manifest = std::fs::read(&manifest_path).context("read WinFsp lease manifest")?;
    if manifest.len() > 64 * 1024 {
        bail!("WinFsp lease manifest exceeds the bounded size");
    }
    let admitted: StorageMountLeaseV1 =
        serde_json::from_slice(&manifest).context("decode WinFsp lease manifest")?;
    if admitted != *lease {
        bail!("WinFsp launch lease does not match the kernel manifest");
    }
    if !launch.mountpoint.is_absolute()
        || launch
            .mountpoint
            .components()
            .any(|component| matches!(component, std::path::Component::ParentDir))
    {
        bail!("WinFsp service mountpoint is malformed");
    }
    if is_public_mountpoint(&launch.mountpoint)
        || launch.mountpoint.parent().is_none()
        || launch.mountpoint == lease.resource_path
        || launch.mountpoint.starts_with(&lease.resource_path)

View on GitHub (pinned to affd8760f4)

Solutions

  1. Delete the bad lease.json and let the issuer regenerate it containing only the StorageMountLeaseV1 struct.
  2. Fix the code that writes lease.json — serialize exactly the StorageMountLeaseV1 value (serde_json::to_writer), not a wrapper with extra fields or embedded data.
  3. Check for file-sync conflict copies or appended content in the resource directory and restore a clean copy.
  4. If legitimately more data is needed, move it to separate files and reference it from the manifest rather than growing the manifest.

Example fix

// before
serde_json::to_writer(&file, &bundle)?; // bundle includes logs + lease
// after
let manifest: StorageMountLeaseV1 = lease_struct_from(bundle);
serde_json::to_writer(&file, &manifest)?;
Defensive patterns

Strategy: validation

Validate before calling

let meta = std::fs::metadata(manifest_path)?;
if meta.len() > 64 * 1024 {
    return Err(anyhow!("lease.json is {} bytes; regenerate it (limit 64 KiB)", meta.len()));
}

Prevention

When it happens

Trigger: service_main -> validate_service_launch where std::fs::read(lease.resource_path.join("lease.json")) returns more than 65536 bytes.

Common situations: A writer accidentally serializes the whole launch bundle (including tokens, buffers, or debug dumps) into lease.json instead of just StorageMountLeaseV1; a crash/partial write concatenated two documents; a user or sync tool (Dropbox/OneDrive conflict copy) grew the file; an attacker or buggy process padded the file.

Understand the failure class

Background: "File too large" / "file size exceeds limit" errors: why libraries cap file sizes and how to fix them — this error's family across 46 libraries.

Related errors


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