astrid-runtime/astrid · error · io::Error
layout migration destination changed while inventoried: {}
Error message
layout migration destination changed while inventoried: {} What it means
While hashing the destination file, inventory_regular_file accumulates the bytes actually read and, after EOF, compares the total with metadata.len() captured at open time. If they differ — the file grew, shrank, or was rewritten while being inventoried — this InvalidData error is raised instead of issuing a receipt for an inconsistent fingerprint. (An arithmetic overflow of the running total raises io::Error::other separately.)
Source
Thrown at crates/astrid-core/src/dirs_layout_records.rs:341
path.display()
),
));
}
let mut hasher = blake3::Hasher::new_derive_key("astrid layout destination inventory v1");
let mut buffer = vec![0_u8; 64 * 1024].into_boxed_slice();
let mut bytes = 0_u64;
loop {
let read = file.read(&mut buffer)?;
if read == 0 {
break;
}
bytes = bytes
.checked_add(read as u64)
.ok_or_else(|| io::Error::other("layout destination length overflow"))?;
hasher.update(&buffer[..read]);
}
if bytes != metadata.len() {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!(
"layout migration destination changed while inventoried: {}",
path.display()
),
));
}
Ok(LayoutTreeIdentityV1 {
path_encoding: "os-str-encoded-bytes-v1".to_owned(),
physical_path_hex: physical_path_hex(path)?,
inventory_algorithm: "blake3-derive-key-v1".to_owned(),
inventory_digest: hasher.finalize().to_hex().to_string(),
entries: 1,
bytes,
})
}
fn inventory_directory(View on GitHub (pinned to affd8760f4)
Solutions
- Quiesce all writers to the destination volume, then re-run the migration/inventory.
- Retry begin_layout_v2_migration when the system is idle so the file is stable during hashing.
- Check for scheduled jobs (backup, sync, logrotate) that touch the volume and exclude the destination path.
Example fix
// before: writers active during inventory // after: ensure exclusive access, then migrate flock /data/astrid-volume # or stop the service holding the volume open, re-run migration
Defensive patterns
Strategy: retry
Validate before calling
let before = std::fs::metadata(&dest_path)?.len();
std::thread::sleep(std::time::Duration::from_secs(1));
if std::fs::metadata(&dest_path)?.len() != before {
return Err("destination is being written; quiesce writers first");
} Try / catch
match begin_layout_v2_migration(...) {
Err(e) if e.to_string().contains("changed while inventoried") => {
quiesce_writers(&dest_path);
retry_with_backoff(begin_layout_v2_migration, 3);
},
other => other,
} Prevention
- Quiesce all writers (stop Astrid, sync clients, backups) before inventory.
- Schedule migrations during idle windows.
- Exclude the volume path from logrotate/snapshot jobs during migration.
When it happens
Trigger: Called from begin_layout_v2_migration / LayoutMigrationReceiptV1 when the destination file's content changes between the metadata() snapshot and the completion of the hashing read loop, so bytes != metadata.len().
Common situations: Astrid itself or another writer appending to/rewriting the volume during migration; log rotation or snapshot tooling truncating the file mid-read; a sync client downloading changes to the destination concurrently.
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
- layout migration destination changed type: {}
- layout migration destination is redirected or not a regular
- layout migration receipt destination path does not match the
- layout migration source is redirected or not a directory: {}
- layout migration source changed type: {}
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/42f6ac0dc5ccb129.
Report an issue: GitHub.