astrid-runtime/astrid · error

message

Error message

message

What it means

invalid_transition is the shared constructor for InvalidData errors raised while decoding or applying volume metadata/footer structures. The displayed message "message" is the function's parameter name; the real message comes from each call site (e.g. "metadata region name is not UTF-8"). It signals that the on-disk structure is inconsistent with the expected format at that point.

Solutions

  1. Read the real message inside the error to identify which structural check failed.
  2. Run recovery (recover_container) so the volume resynchronizes to the last valid commit.
  3. Confirm the writer and reader use compatible astrid-storage versions/formats.
  4. Restore the volume from backup if the footer/metadata region is physically corrupt.
Defensive patterns

Strategy: try-catch

Try / catch

match decode_metadata(file, offset) {
    Err(e) if e.kind() == io::ErrorKind::InvalidData => {
        eprintln!("metadata structure invalid: {e}; running recovery");
        recover_container(file)?;
    }
    other => other,
}

Prevention

When it happens

Trigger: Any of its callers hit malformed data: decode_metadata_mutations reading bad kind/length fields, read_u16 or read_metadata_region hitting EOF mid-field, a region name failing UTF-8 validation, encode_region_snapshot/write_footer invariant failures, or apply_metadata_mutations encountering an impossible region transition.

Common situations: Disk corruption or torn writes in the volume footer/metadata area; a volume written by a different (incompatible) format version; manually editing or truncating the volume file; decoding at a stale offset after an interrupted commit.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/a8b984b585ef277f. Report an issue: GitHub.

Appendix: source

Thrown at crates/astrid-storage/src/volume/hosted/mod.rs:592

    })?))
}

fn read_metadata_region(bytes: &[u8], cursor: &mut usize) -> io::Result<VolumeRegion> {
    let length = usize::from(read_u16(bytes, cursor)?);
    let end = cursor
        .checked_add(length)
        .ok_or_else(|| invalid_transition("metadata region name length overflow"))?;
    let name = bytes
        .get(*cursor..end)
        .ok_or_else(|| invalid_transition("truncated metadata region name"))?;
    *cursor = end;
    let name = std::str::from_utf8(name)
        .map_err(|_| invalid_transition("metadata region name is not UTF-8"))?;
    VolumeRegion::new(name.to_owned())
}

fn invalid_transition(message: &'static str) -> io::Error {
    io::Error::new(io::ErrorKind::InvalidData, message)
}

fn overlapping_extents(
    region_state: &RegionState,
    offset: u64,
    read_end: u64,
) -> Vec<(u64, Extent)> {
    let start_key = region_state
        .extents
        .range(..=offset)
        .next_back()
        .and_then(|(start, extent)| (extent.logical_end > offset).then_some(*start))
        .unwrap_or(offset);
    let mut overlaps = Vec::new();
    for (start, extent) in region_state.extents.range(start_key..read_end) {
        #[cfg(test)]
        EXTENT_VISITS.with(|count| count.set(count.get().saturating_add(1)));
        if extent.logical_end > offset {

View on GitHub (pinned to affd8760f4)