astrid-runtime/astrid · error
InvalidData
InvalidData
Error message
installed executable digest changed: {} What it means
At the end of an executable replacement transaction, the library re-reads the live file and compares its digest to the hash recorded when the entry was staged. If the on-disk digest differs, the file changed between staging and commit (or the write was corrupted), so the transaction aborts with InvalidData rather than trusting a modified executable.
Source
Thrown at crates/astrid-core/src/platform_fs/windows/executable.rs:143
"executable transaction commit",
BoundaryContract::TrustedForCreate,
|| {
for (index, entry) in journal.entries.iter().enumerate() {
let live = install_dir.join(&entry.name);
let staged = install_dir.join(&entry.staged);
if entry.had_live {
replace_file_checked(install_guard, &live, &staged)?;
} else {
move_guarded_file(install_guard, &staged, &live)?;
}
if hash_guarded_regular_file(
install_guard,
&live,
FileContract::Trusted,
BoundaryContract::TrustedForCreate,
)? != entry.new_hash
{
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!("installed executable digest changed: {}", live.display()),
));
}
test_maybe_interrupt_after_replace(index);
}
// Preserve the prior authenticated executables as conventional backups.
// Rollback copies stay independent and live until the journal commit point.
for entry in &journal.entries {
if let Some(rollback_name) = &entry.rollback {
let rollback = install_dir.join(rollback_name);
let backup = install_dir.join(format!("{}.bak", entry.name));
let staged_backup = stage_transaction_copy(
install_guard,
install_guard,
FileContract::ExactPrivate,
BoundaryContract::TrustedForCreate,View on GitHub (pinned to affd8760f4)
Solutions
- Re-run the replacement transaction from scratch so the hash is recomputed against current bytes
- Check antivirus/EDR logs for quarantine or modification of the installed executable and add an exclusion
- Ensure no other updater or process writes to the install directory concurrently
- Verify disk health (chkdsk / SMART) if corruption recurs
Example fix
// before: comparing after the fact fails because AV rewrote the file
// after: detect and retry the whole transaction once
match replace_executable_set(...) {
Err(e) if e.kind() == io::ErrorKind::InvalidData && e.to_string().contains("digest changed") => {
// re-stage with fresh bytes and retry once
}
other => other?,
} Defensive patterns
Strategy: validation
Validate before calling
// Verify the live file digest before committing the transaction
fn live_digest_matches(live: &std::path::Path, expected_hash: &str) -> bool {
std::fs::read(live).map(|bytes| hash(&bytes) == expected_hash).unwrap_or(false)
} Try / catch
match replace_executable_set(...) {
Err(e) if e.to_string().starts_with("installed executable digest changed") => {
eprintln!("Executable changed mid-transaction; re-stage and retry once");
}
other => other?,
} Prevention
- Exclude the install directory from AV quarantine/rewrite during updates
- Ensure only one updater process runs at a time (single-instance lock)
- Never write to installed executables outside the transaction API
- Verify disk health if mismatches recur
When it happens
Trigger: finish_executable_transaction (via replace_executable_set) computes the live file hash under the install guard with FileContract::Trusted and it differs from entry.new_hash — e.g. another writer modified the file mid-transaction or the staged bytes did not land intact.
Common situations: Antivirus quarantining or rewriting the freshly installed executable; a second updater process racing the transaction; disk corruption or incomplete flush before commit; user/tooling editing the file between prepare and finish.
Understand the failure class
Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.
Related errors
- InvalidInput
- AlreadyExists
- capsule '{}' hash mismatch: signed lock has {}, resolved art
- signed Distro.lock entry '{}' has no capsule hash
- PermissionDenied
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/b1d6d7a0c8d18792.
Report an issue: GitHub.