astrid-runtime/astrid · error

WinFsp service parent token is invalid

Error message

WinFsp service parent token is invalid

What it means

validate_service_launch requires the parent token to be 16-512 characters long with no control characters. The token authenticates the child back to the parent (used in the ready challenge), so an empty, oversized, or control-character-laden token is rejected as invalid. An optional start_identity, if present, has the same constraints.

Source

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

    stdout.flush().context("flush WinFsp readiness")?;

    let result = private_service_loop(filesystem, listener, &launch).await;
    let _ = local_transport::remove_endpoint(&launch.control_path);
    result
}

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 {

View on GitHub (pinned to affd8760f4)

Solutions

  1. Generate the parent token with a proper random source (e.g. 32+ random bytes hex/base64-encoded, no control chars)
  2. Trim/strip whitespace and newlines when loading the token from env or a file
  3. Validate the token length (16-512) and character set before writing the launch document
  4. Do the same checks for start_identity or leave it as None if not needed

Example fix

// before
let token = format!("launch-{}\n", short_id()); // 9 chars + newline
// after
let token: String = rand::thread_rng()
    .sample_iter(&rand::distributions::Alphanumeric)
    .take(32).collect();
Defensive patterns

Strategy: validation

Validate before calling

let t = &launch.parent.token;
if t.len() < 16 || t.len() > 512 || t.chars().any(char::is_control) {
    return Err("parent token must be 16-512 chars with no control characters".into());
}
if let Some(id) = launch.parent.start_identity.as_deref() {
    if id.is_empty() || id.len() > 512 || id.chars().any(char::is_control) {
        return Err("start_identity must be 1-512 chars with no control characters".into());
    }
}

Type guard

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

Try / catch

match service_err {
    Err(e) if e.to_string().contains("parent token is invalid") => {
        eprintln!("regenerate token with a proper random source, strip whitespace");
    }
    other => other?,
}

Prevention

When it happens

Trigger: The launch document has parent.token shorter than 16 chars, longer than 512, containing control characters (e.g. embedded newlines or null bytes), or parent.start_identity set to an empty/oversized/control-char string.

Common situations: Generating the token with a weak/custom source that yields too few characters; concatenating fields with '\n' into the token; loading the token from an env var or file that includes trailing newlines; truncating the token at a fixed buffer boundary.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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