{"record":{"id":"0c65d42008fb9433","repo":"astrid-runtime/astrid","slug":"invaliddata-0c65d4","errorCode":"InvalidData","errorMessage":"staged executable does not match its locked source handle","messagePattern":"staged executable does not match its locked source handle","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/astrid-core/src/platform_fs/windows/io.rs","lineNumber":241,"sourceCode":"    file_name: &str,\n) -> io::Result<(PathBuf, String)> {\n    let source_path = source;\n    let mut source_file =\n        open_guarded_regular_file(source_guard, source_path, source_file_contract)?;\n    let source_identity = file_identity(&source_file)?;\n    let source_hash = hash_open_file(&mut source_file)?;\n    source_file.seek(io::SeekFrom::Start(0))?;\n    let destination = install_dir.join(file_name);\n    let mut output = create_guarded_private_file(destination_guard, &destination)?;\n    let mut cleanup = PreparationCleanup::new(destination_guard);\n    cleanup.track(destination.clone());\n    let result = (|| {\n        io::copy(&mut source_file, &mut output)?;\n        output.flush()?;\n        output.sync_all()?;\n        let staged_hash = hash_open_file(&mut output)?;\n        if staged_hash != source_hash {\n            return Err(io::Error::new(\n                io::ErrorKind::InvalidData,\n                \"staged executable does not match its locked source handle\",\n            ));\n        }\n        validate_private_acl_handle(\n            output.as_raw_handle().cast(),\n            false,\n            &destination.display().to_string(),\n        )?;\n        Ok(())\n    })();\n    drop(output);\n    if let Err(error) = result {\n        let _ = remove_guarded_file(destination_guard, &destination);\n        return Err(error);\n    }\n    if let Err(error) = validate_file_contract(\n        source_file.as_raw_handle().cast(),","sourceCodeStart":223,"sourceCodeEnd":259,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-core/src/platform_fs/windows/io.rs#L223-L259","documentation":"This error is raised during an authenticated staging copy of an executable (prepare_executable_transaction and related staging APIs). After copying the source file into a private staged file, the library re-hashes the staged bytes and compares them against the hash of the locked source handle. A mismatch means the bytes that landed on disk differ from what the locked source contained — the library refuses to proceed rather than install a corrupted or tampered binary, and removes the staged copy.","triggerScenarios":"Raised in stage_transaction_copy_authenticated when `staged_hash != source_hash` after `io::copy` + flush + sync_all of the source executable into the guarded private destination file. This happens when the source file contents mutate under the open handle during the copy (another process writes to it despite the share lock), copy/flush I/O silently drops or corrupts data (disk full, failing storage), or an FS filter/antivirus rewrites bytes mid-copy.","commonSituations":"Antivirus or EDR software quarantining or modifying an executable during download/install; another updater process racing to overwrite the same source binary; disk corruption or out-of-space conditions on the target volume; users manually replacing an exe while an update transaction is running.","solutions":["Close any process that could be writing to the source executable (other updaters, editors, sync clients) and retry the transaction.","Add an antivirus/EDR exclusion for the install and staging directories so filters stop rewriting the binary mid-copy.","Verify free disk space and filesystem health (chkdsk) on the volume holding the staging directory.","Re-fetch the source executable from a trusted origin so the staged hash matches a known-good source, then retry."],"exampleFix":"// before: copying from a source that another process may rewrite in place\nlet hash = hash_open_file(&mut source_file)?;\nsource_file.seek(SeekFrom::Start(0))?;\nio::copy(&mut source_file, &mut output)?; // source mutated concurrently -> hash mismatch\n// after: ensure exclusive access first (open with no share modes, as the library does\n// via open_guarded_child_locked) and verify identity after copy\nlet identity = file_identity(&source_file)?;\nlet hash = hash_open_file(&mut source_file)?;\nsource_file.seek(SeekFrom::Start(0))?;\nio::copy(&mut source_file, &mut output)?;\nassert_eq!(file_identity(&source_file)?, identity, \"source changed during copy\");","handlingStrategy":"try-catch","validationCode":"// Rust: pre-check free space and ensure no competing writers before staging\nlet meta = fs::metadata(&source)?;\nlet avail = fs2::available_space(&install_dir)?;\nif avail < meta.len() * 2 {\n    return Err(io::Error::new(io::ErrorKind::StorageFull, \"insufficient space for staging\"));\n}","typeGuard":null,"tryCatchPattern":"// Rust\nmatch prepare_executable_transaction(/* args */) {\n    Ok(plan) => commit(plan),\n    Err(e) if e.kind() == io::ErrorKind::InvalidData\n        && e.to_string().contains(\"staged executable does not match\") => {\n        // integrity failure: kill competing writers, exclude AV paths, retry once\n        eprintln!(\"staged copy corrupted (AV or concurrent write?): {e}\");\n        retry_with_exclusive_source_lock();\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Run only one updater/installer instance per install directory (cross-process lock).","Add antivirus/EDR exclusions for install and staging directories.","Monitor free disk space before starting transactions.","Retry transactions from a freshly verified source after integrity failures."],"tags":["windows","filesystem","integrity-check","checksum-mismatch","staging"],"backgroundTag":"checksum-mismatch","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"}