astrid-runtime/astrid · error

WinFsp service parent start identity is invalid

Error message

WinFsp service parent start identity is invalid

What it means

The WinFsp mount service validates that the launching parent supplied a start_identity string. This error fires when start_identity is present (Some) but fails sanity checks: it is empty, longer than 512 bytes, or contains Unicode control characters. The library rejects it before starting the filesystem because the identity is used for service-attribution/audit and an unbounded or control-character-laden value is treated as a malformed or hostile launch descriptor.

Source

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

}

fn validate_service_launch(launch: &StorageProviderServiceLaunchV1) -> Result<()> {
    if launch.schema != STORAGE_FILESYSTEM_SERVICE_LAUNCH_SCHEMA_V1 {
        bail!("unsupported WinFsp service launch schema {}", launch.schema);
    }
    if launch.parent.pid <= 1 || launch.parent.pid == std::process::id() {
        bail!("WinFsp service parent PID is invalid");
    }
    if launch.parent.token.len() < 16
        || launch.parent.token.len() > 512
        || launch.parent.token.chars().any(char::is_control)
    {
        bail!("WinFsp service parent token is invalid");
    }
    if let Some(identity) = launch.parent.start_identity.as_deref()
        && (identity.is_empty() || identity.len() > 512 || identity.chars().any(char::is_control))
    {
        bail!("WinFsp service parent start identity is invalid");
    }
    if launch.parent.start_identity.is_none() {
        bail!("WinFsp service parent start identity is required on Windows");
    }
    let lease = &launch.lease;
    let now = SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .context("read system clock")?
        .as_secs();
    if lease.expires_at_epoch_secs < now {
        bail!("WinFsp lease is expired");
    }
    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")

View on GitHub (pinned to affd8760f4)

Solutions

  1. In the launching parent, set start_identity to a non-empty, trimmed string no longer than 512 chars; if there is no identity, serialize None rather than an empty string.
  2. Strip control characters and trim the identity before building the launch descriptor (retain char::is_control filter).
  3. Log/inspect the exact identity bytes being written to the launch file to find where control characters or overlong values originate.
  4. If the identity legitimately needs more room, shorten it (e.g. store an ID/reference, not a full description) since 512 is a hard limit in this validator.

Example fix

// before
parent.start_identity = Some(format!("{}\n{}", user, host));
// after
let identity: String = format!("{} {}", user, host).chars().filter(|c| !c.is_control()).collect();
parent.start_identity = if identity.is_empty() || identity.len() > 512 { None } else { Some(identity) };
Defensive patterns

Strategy: validation

Validate before calling

fn valid_start_identity(s: &Option<String>) -> bool {
    match s {
        Some(s) => !s.is_empty() && s.len() <= 512 && !s.chars().any(char::is_control),
        None => false,
    }
}
assert!(valid_start_identity(&launch.parent.start_identity), "invalid start_identity");

Type guard

fn is_ok_identity(s: Option<&str>) -> bool {
    matches!(s, Some(v) if !v.is_empty() && v.len() <= 512 && !v.chars().any(char::is_control))
}

Prevention

When it happens

Trigger: service_main -> validate_service_launch receives a StorageProviderServiceLaunchV1 whose launch.parent.start_identity is Some(s) where s.is_empty(), s.len() > 512, or s.chars().any(char::is_control). I.e., the parent process serialized a non-empty but invalid identity string into the launch descriptor.

Common situations: A launcher passes "" (empty string) instead of None when the identity is unknown; a config/registry field for the mount identity accumulates whitespace/newlines or other control chars; a truncated or concatenated identity from an IPC buffer exceeds 512 chars; templates that interpolate an account name into the identity pick up stray \0 or \r\n.

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/a63ca385a0548574. Report an issue: GitHub.