astrid-runtime/astrid · error
destination.as_str()
Error message
destination.as_str()
What it means
rename_region rejects the operation with io::ErrorKind::AlreadyExists and the destination name when a region with that name already exists in the volume. Renames must produce a fresh name; the library refuses to silently overwrite an existing region (use replace_region for overwrite semantics).
Solutions
- Use replace_region instead when overwrite of an existing destination is intended.
- Delete the existing destination with remove_region before renaming, if the old contents are disposable.
- Generate a unique destination name (counter/uuid suffix) when creating new generations.
- Catch io::ErrorKind::AlreadyExists and branch to overwrite-or-skip logic at the call site.
Example fix
// before
volume.rename_region(&src, &dst)?; // AlreadyExists if dst exists
// after
if volume.region_exists(&dst) {
volume.replace_region(&src, &dst)?;
} else {
volume.rename_region(&src, &dst)?;
} Defensive patterns
Strategy: validation
Validate before calling
if region_exists(&volume, &dst) {
volume.replace_region(&src, &dst)?; // or remove dst first
} else {
volume.rename_region(&src, &dst)?;
} Type guard
fn rename_target_free(dst: &VolumeRegion, existing: &[String]) -> bool {
!existing.iter().any(|r| r == dst.as_str())
} Try / catch
if let Err(e) = volume.rename_region(&src, &dst) {
if e.kind() == io::ErrorKind::AlreadyExists {
// choose: overwrite via replace_region, or skip as already-done
} else {
return Err(e);
}
} Prevention
- Use unique destination names (uuid/monotonic counter) for new generations.
- Remember rename_region never overwrites; reach for replace_region for swap-over semantics.
- In retry logic, check whether the rename already succeeded (src gone, dst present).
- Clean up stale destination regions left by previous failed runs.
When it happens
Trigger: Calling rename_region(source, destination) where state.regions already contains destination: renaming onto a region created earlier, renaming to the region's own current name, or a leftover destination region from a prior run persisted in the volume file.
Common situations: Retry logic re-attempting a rename that already succeeded; installing a new generation over an old region name without deleting the old one first; generated destination names colliding (e.g. same timestamp); user expecting POSIX rename() overwrite semantics.
Understand the failure class
Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.
Related errors
- region.as_str()
- source.as_str()
- audit read failed
- invalid Astrid volume record length at
- invalid interior Astrid volume record length at
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/9b957420cd9f79fc.
Report an issue: GitHub.
Appendix: source
Thrown at crates/astrid-storage/src/volume/hosted/mod.rs:335
truncate_extents(&mut region_state.extents, length);
region_state.length = length;
Ok(())
}
fn remove_region(&self, region: &VolumeRegion) -> io::Result<()> {
let mut state = self.state.lock();
if !state.regions.contains_key(region) {
return Err(io::Error::new(io::ErrorKind::NotFound, region.as_str()));
}
Self::append(&mut state, Operation::Remove, region, 0, &[])?;
state.regions.remove(region);
Ok(())
}
fn rename_region(&self, source: &VolumeRegion, destination: &VolumeRegion) -> io::Result<()> {
let mut state = self.state.lock();
if state.regions.contains_key(destination) {
return Err(io::Error::new(
io::ErrorKind::AlreadyExists,
destination.as_str(),
));
}
if !state.regions.contains_key(source) {
return Err(io::Error::new(io::ErrorKind::NotFound, source.as_str()));
}
Self::append(
&mut state,
Operation::Rename,
source,
0,
destination.as_str().as_bytes(),
)?;
let source_state = state
.regions
.remove(source)
.ok_or_else(|| io::Error::new(io::ErrorKind::NotFound, source.as_str()))?;View on GitHub (pinned to affd8760f4)