astrid-runtime/astrid · error · io::Error

cannot migrate an Astrid home without a layout-version senti

Error message

cannot migrate an Astrid home without a layout-version sentinel

What it means

begin_layout_v2_migration in crates/astrid-core/src/dirs_layout.rs:166 refuses to start a layout-v2 migration when the Astrid home has no layout-version sentinel file at all (layout_version() returns None). Migration only runs from a known legacy version (LEGACY_LAYOUT_VERSION); a home with no sentinel is unrecognized state, so the operation fails with InvalidData to avoid guessing the layout.

Source

Thrown at crates/astrid-core/src/dirs_layout.rs:166

        self.var_dir().join("migrations")
    }

    /// Persist the content-bound layout migration intent before opening stores.
    ///
    /// The caller must hold the daemon singleton lock. Re-entry accepts only
    /// the exact same source inventory, destination format, physical roots, and
    /// executable identity.
    ///
    /// # Errors
    ///
    /// Returns an error for unsupported layouts, redirected paths, invalid
    /// source content, or a prior intent for a different transaction.
    pub fn begin_layout_v2_migration(&self, target: &LayoutMigrationTarget) -> io::Result<()> {
        match self.layout_version()?.as_deref() {
            Some(LAYOUT_VERSION) => return Ok(()),
            Some(LEGACY_LAYOUT_VERSION) => {},
            None => {
                return Err(io::Error::new(
                    io::ErrorKind::InvalidData,
                    "cannot migrate an Astrid home without a layout-version sentinel",
                ));
            },
            Some(other) => {
                return Err(io::Error::new(
                    io::ErrorKind::InvalidData,
                    format!("unsupported Astrid home layout version {other:?}"),
                ));
            },
        }
        reject_automatic_windows_layout_one()?;
        self.preflight_layout_v2_paths()?;
        for path in [
            self.storage_volume_path(),
            self.legacy_storage_volume_path(),
            self.retired_root_storage_volume_path(),
        ] {

View on GitHub (pinned to affd8760f4)

Solutions

  1. Initialize the Astrid home first (run the app/installer's init) so a valid layout-version sentinel is written, then migrate if needed.
  2. Restore the missing layout-version sentinel from backup if the home content is otherwise intact.
  3. Confirm you are pointing at the correct home directory — a fresh/empty home cannot be migrated.
  4. If the home is genuinely uninitialized, no migration is needed; skip begin_layout_v2_migration.

Example fix

// before
let dirs = AstridDirs::at(empty_home)?;
dirs.begin_layout_v2_migration(&target)?; // InvalidData: no sentinel

// after
if dirs.layout_version()?.is_none() {
    dirs.initialize_home()?; // writes layout-version sentinel
}
dirs.begin_layout_v2_migration(&target)?;
Defensive patterns

Strategy: validation

Validate before calling

// Rust
fn migration_possible(dirs: &AstridDirs) -> io::Result<bool> {
    Ok(dirs.layout_version()?.is_some()) // None means begin_layout_v2_migration will fail
}

Try / catch

match home.layout_version() {
    Ok(None) => {
        // no sentinel: initialize the home first or skip migration entirely
    }
    Ok(Some(v)) if v == LAYOUT_VERSION => { /* already migrated */ }
    Ok(Some(_)) => home.begin_layout_v2_migration(&target)?,
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling begin_layout_v2_migration on an Astrid home directory that was never initialized by any version (sentinel never written), or where the sentinel file was deleted/corrupted so it cannot be read.

Common situations: Running migration against a blank/fresh home directory by mistake; manual cleanup or disk-cleanup tools deleting the version sentinel; restoring a partial backup that omitted the sentinel file.

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/8270357aa4c4ec80. Report an issue: GitHub.