{"record":{"id":"3e1a7c18114d07d6","repo":"astrid-runtime/astrid","slug":"fskit-callback-probe-protocol-mismatch","errorCode":null,"errorMessage":"FSKit callback probe protocol mismatch","messagePattern":"FSKit callback probe protocol mismatch","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-storage-provider-fskit/src/service.rs","lineNumber":254,"sourceCode":"        StorageFilesystemOutcomeV2::Failure(StorageFilesystemFailureV1 { code, message }) => {\n            bail!(\"FSKit callback probe failed [{code}]: {message}\")\n        },\n    }\n}\n\nasync fn read_callback_response(stream: &mut LocalStream) -> Result<StorageFilesystemResponseV2> {\n    let mut length = [0_u8; 4];\n    stream.read_exact(&mut length).await?;\n    let length = u32::from_be_bytes(length) as usize;\n    if length == 0 || length > MAX_CALLBACK_BYTES {\n        bail!(\"FSKit callback response exceeds the bounded frame size\");\n    }\n    let mut bytes = vec![0_u8; length];\n    stream.read_exact(&mut bytes).await?;\n    let response: StorageFilesystemResponseV2 =\n        serde_json::from_slice(&bytes).context(\"decode FSKit callback probe\")?;\n    if response.protocol_version != STORAGE_FILESYSTEM_PROTOCOL_V2 {\n        bail!(\"FSKit callback probe protocol mismatch\");\n    }\n    Ok(response)\n}\n\nasync fn service_loop(\n    listener: &LocalListener,\n    launch: &StorageProviderServiceLaunchV1,\n    mounted: &mut bool,\n) -> Result<()> {\n    let mut poll = tokio::time::interval(SERVICE_POLL);\n    loop {\n        tokio::select! {\n            accepted = local_transport::accept(listener) => {\n                let mut stream = accepted.context(\"accept FSKit service control\")?;\n                let request = read_control(&mut stream).await?;\n                let (response, stop) = match request {\n                    ControlRequest::Status { token } if token == launch.parent.token => {\n                        (ControlResponse::Ready, false)","sourceCodeStart":236,"sourceCodeEnd":272,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-storage-provider-fskit/src/service.rs#L236-L272","documentation":"read_callback_response deserializes the framed JSON into StorageFilesystemResponseV2 and requires response.protocol_version to equal STORAGE_FILESYSTEM_PROTOCOL_V2. A different version means the peer speaks an incompatible protocol revision, so the response is rejected rather than misinterpreted.","triggerScenarios":"read_callback_response (called by probe_callback) parses a well-framed response whose protocol_version != STORAGE_FILESYSTEM_PROTOCOL_V2 — typically an older or newer extension responding on the socket.","commonSituations":"Version skew after upgrading the Rust provider but not the bundled FSKit extension (or vice versa); a legacy V1 responder still running; a test stub hard-coding another version constant.","solutions":["Upgrade the FSKit extension to the build that speaks STORAGE_FILESYSTEM_PROTOCOL_V2","Check for a stale extension binary/process and restart the service so the current one is used","Align the protocol constant across provider and extension (bump both together)","If migrating intentionally, add a version negotiation step before probing"],"exampleFix":"// extension side\n// before\nresponse.protocolVersion = 1\n// after\nresponse.protocolVersion = STORAGE_FILESYSTEM_PROTOCOL_V2","handlingStrategy":"validation","validationCode":"fn protocol_ok(resp: &StorageFilesystemResponseV2) -> bool { resp.protocol_version == STORAGE_FILESYSTEM_PROTOCOL_V2 }","typeGuard":null,"tryCatchPattern":"if let Err(e) = read_callback_response(&mut stream).await { if e.to_string().contains(\"protocol mismatch\") { report_version_skew(); } }","preventionTips":["Deploy provider and extension upgrades together","Add a version handshake before probes","Restart services after upgrades to kill stale responders","Pin the protocol constant in a shared definition"],"tags":["ipc","protocol","versioning"],"backgroundTag":"incompatible-source-type","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"}