{"record":{"id":"1a0699415bfde94e","repo":"astrid-runtime/astrid","slug":"winfsp-callback-probe-protocol-mismatch","errorCode":null,"errorMessage":"WinFsp callback probe protocol mismatch","messagePattern":"WinFsp callback probe protocol mismatch","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-storage-provider-winfsp/src/win.rs","lineNumber":366,"sourceCode":"        },\n    };\n    let bytes = serde_json::to_vec(&request).context(\"encode WinFsp callback probe\")?;\n    let length = u32::try_from(bytes.len()).context(\"WinFsp callback probe is too large\")?;\n    stream.write_all(&length.to_be_bytes()).await?;\n    stream.write_all(&bytes).await?;\n    stream.flush().await?;\n    let mut response_length = [0_u8; 4];\n    stream.read_exact(&mut response_length).await?;\n    let length = u32::from_be_bytes(response_length) as usize;\n    if length == 0 || length > SERVICE_MAX_CALLBACK_BYTES {\n        bail!(\"WinFsp callback response exceeds limit\");\n    }\n    let mut response_bytes = vec![0_u8; length];\n    stream.read_exact(&mut response_bytes).await?;\n    let response: StorageFilesystemResponseV2 =\n        serde_json::from_slice(&response_bytes).context(\"decode WinFsp callback probe\")?;\n    if response.protocol_version != STORAGE_FILESYSTEM_PROTOCOL_V2 {\n        bail!(\"WinFsp callback probe protocol mismatch\");\n    }\n    if response.request_id != request.request_id {\n        bail!(\"WinFsp callback probe correlation mismatch\");\n    }\n    match response.outcome {\n        StorageFilesystemOutcomeV2::Success(_) => Ok(()),\n        StorageFilesystemOutcomeV2::Failure(StorageFilesystemFailureV1 { code, message }) => {\n            bail!(\"WinFsp callback probe failed [{code}]: {message}\")\n        },\n    }\n}\n\nasync fn private_service_loop(\n    filesystem: FileSystem,\n    listener: local_transport::LocalListener,\n    launch: &StorageProviderServiceLaunchV1,\n) -> Result<()> {\n    let mut filesystem = Some(filesystem);","sourceCodeStart":348,"sourceCodeEnd":384,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-storage-provider-winfsp/src/win.rs#L348-L384","documentation":"probe_callback requires every StorageFilesystemResponseV2 to carry protocol_version == STORAGE_FILESYSTEM_PROTOCOL_V2. A well-formed but differently-versioned response is rejected, protecting the daemon from talking to an incompatible callback implementation.","triggerScenarios":"run_private_service -> probe_callback when the responder answers the probe with a serialized StorageFilesystemResponseV2 whose protocol_version field differs from STORAGE_FILESYSTEM_PROTOCOL_V2 (older v1 responder, or newer protocol bump).","commonSituations":"Mixed-version deployment: daemon built against protocol v2 but callback library still v1; after upgrading the storage crate one side wasn't rebuilt; a different service answering on callback_path with its own protocol constant.","solutions":["Rebuild/upgrade the callback responder so its protocol_version equals STORAGE_FILESYSTEM_PROTOCOL_V2.","Align crate versions of the daemon and callback library (same workspace revision) and re-deploy both.","Confirm the process answering on callback_path is actually the expected astrid callback, not another service.","If you intentionally bumped the protocol, update STORAGE_FILESYSTEM_PROTOCOL_V2 and the wire format on both sides together."],"exampleFix":"// before (responder)\nStorageFilesystemResponseV2 { protocol_version: STORAGE_FILESYSTEM_PROTOCOL_V1, .. }\n// after\nStorageFilesystemResponseV2 { protocol_version: STORAGE_FILESYSTEM_PROTOCOL_V2, .. }","handlingStrategy":"type-guard","validationCode":"fn response_version_ok(resp: &StorageFilesystemResponseV2) -> bool {\n    resp.protocol_version == STORAGE_FILESYSTEM_PROTOCOL_V2\n}","typeGuard":"fn is_v2_response(resp: &StorageFilesystemResponseV2) -> bool {\n    resp.protocol_version == STORAGE_FILESYSTEM_PROTOCOL_V2\n}","tryCatchPattern":"match probe_callback(&launch, &request).await {\n    Err(e) if e.to_string().contains(\"protocol mismatch\") => {\n        // pin both sides to the same crate version, then retry\n        Err(e)\n    },\n    other => other,\n}","preventionTips":["Keep the daemon and callback library on identical crate versions in your lockfile.","Guard the responder against accepting requests with an unknown protocol version.","Add a cross-version CI test so protocol bumps fail loudly."],"tags":["protocol","version-mismatch","winfsp"],"backgroundTag":"schema-validation-failed","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}