{"record":{"id":"768227649afbf618","repo":"astrid-runtime/astrid","slug":"winfsp-service-parent-token-is-invalid","errorCode":null,"errorMessage":"WinFsp service parent token is invalid","messagePattern":"WinFsp service parent token is invalid","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-storage-provider-winfsp/src/win.rs","lineNumber":247,"sourceCode":"    stdout.flush().context(\"flush WinFsp readiness\")?;\n\n    let result = private_service_loop(filesystem, listener, &launch).await;\n    let _ = local_transport::remove_endpoint(&launch.control_path);\n    result\n}\n\nfn validate_service_launch(launch: &StorageProviderServiceLaunchV1) -> Result<()> {\n    if launch.schema != STORAGE_FILESYSTEM_SERVICE_LAUNCH_SCHEMA_V1 {\n        bail!(\"unsupported WinFsp service launch schema {}\", launch.schema);\n    }\n    if launch.parent.pid <= 1 || launch.parent.pid == std::process::id() {\n        bail!(\"WinFsp service parent PID is invalid\");\n    }\n    if launch.parent.token.len() < 16\n        || launch.parent.token.len() > 512\n        || launch.parent.token.chars().any(char::is_control)\n    {\n        bail!(\"WinFsp service parent token is invalid\");\n    }\n    if let Some(identity) = launch.parent.start_identity.as_deref()\n        && (identity.is_empty() || identity.len() > 512 || identity.chars().any(char::is_control))\n    {\n        bail!(\"WinFsp service parent start identity is invalid\");\n    }\n    if launch.parent.start_identity.is_none() {\n        bail!(\"WinFsp service parent start identity is required on Windows\");\n    }\n    let lease = &launch.lease;\n    let now = SystemTime::now()\n        .duration_since(UNIX_EPOCH)\n        .context(\"read system clock\")?\n        .as_secs();\n    if lease.expires_at_epoch_secs < now {\n        bail!(\"WinFsp lease is expired\");\n    }\n    if lease.lease_token.len() < 16 || lease.lease_token.len() > 4096 {","sourceCodeStart":229,"sourceCodeEnd":265,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-storage-provider-winfsp/src/win.rs#L229-L265","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Generate the parent token with a proper random source (e.g. 32+ random bytes hex/base64-encoded, no control chars)","Trim/strip whitespace and newlines when loading the token from env or a file","Validate the token length (16-512) and character set before writing the launch document","Do the same checks for start_identity or leave it as None if not needed"],"exampleFix":"// before\nlet token = format!(\"launch-{}\\n\", short_id()); // 9 chars + newline\n// after\nlet token: String = rand::thread_rng()\n    .sample_iter(&rand::distributions::Alphanumeric)\n    .take(32).collect();","handlingStrategy":"validation","validationCode":"let t = &launch.parent.token;\nif t.len() < 16 || t.len() > 512 || t.chars().any(char::is_control) {\n    return Err(\"parent token must be 16-512 chars with no control characters\".into());\n}\nif let Some(id) = launch.parent.start_identity.as_deref() {\n    if id.is_empty() || id.len() > 512 || id.chars().any(char::is_control) {\n        return Err(\"start_identity must be 1-512 chars with no control characters\".into());\n    }\n}","typeGuard":"fn is_valid_parent_token(t: &str) -> bool {\n    (16..=512).contains(&t.len()) && !t.chars().any(char::is_control)\n}","tryCatchPattern":"match service_err {\n    Err(e) if e.to_string().contains(\"parent token is invalid\") => {\n        eprintln!(\"regenerate token with a proper random source, strip whitespace\");\n    }\n    other => other?,\n}","preventionTips":["Generate tokens with a CSPRNG at 32+ bytes","Trim newlines when loading tokens from env/files","Never embed control characters by concatenation","Validate tokens before serializing the launch document"],"tags":["windows","winfsp","validation","token"],"backgroundTag":"invalid-argument-format","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}