astrid-runtime/astrid · error

invalid logical destination

Error message

invalid logical destination {destination}: {error}

What it means

Raised by preflight_entry when the entry.destination string from a migration entry cannot be converted into a valid logical FilesystemPath. The underlying FilesystemPath parse error is embedded. Preflight aborts before any filesystem mutation.

Solutions

  1. Check the {destination} value in the receipt for syntax problems (empty, '..', absolute/relative mix)
  2. Regenerate the migration receipt from a trustworthy source
  3. Repair the receipt's destination field to a valid logical path
  4. Restore receipts from backup if they were corrupted

Example fix

// before: corrupt destination string in receipt
"destination": "uploads//../../etc"
// after: sanitized logical destination
"destination": "uploads/principal-a/file.bin"
Defensive patterns

Strategy: validation

Validate before calling

fn destination_is_valid(dest: &str) -> bool {
    !dest.is_empty() && FilesystemPath::new(dest.to_string()).is_ok()
}

Type guard

fn parse_logical_path(s: &str) -> Option<FilesystemPath> { FilesystemPath::new(s.to_string()).ok() }

Try / catch

match preflight_result {
    Err(e) if e.kind() == io::ErrorKind::InvalidData => report_bad_receipt_entry(e),
    Err(e) => return Err(e),
    Ok(()) => proceed(),
}

Prevention

When it happens

Trigger: Calling migrate_one_principal -> preflight_entry with a MigrationEntry whose destination field is malformed (empty string, illegal components, path traversal, invalid logical path syntax).

Common situations: Corrupted or hand-edited migration receipt files, destinations produced by an older buggy writer, or receipts copied between systems with different path conventions.

Understand the failure class

Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.

Related errors


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

Appendix: source

Thrown at crates/astrid-kernel/src/principal_home_migration/mod.rs:603

            bytes: self.bytes,
        }
    }
}

fn preflight_entry(
    filesystem: &AstridFilesystem<
        StateOwner,
        astrid_storage::engine::DurableEngine<
            StateOwner,
            astrid_storage::Blake3ObjectIdentityV1,
            astrid_storage::StateOwnerCodecV2,
        >,
    >,
    source_root: &Path,
    entry: &MigrationEntry,
) -> io::Result<()> {
    let destination = FilesystemPath::new(entry.destination.clone()).map_err(|error| {
        io::Error::new(
            io::ErrorKind::InvalidData,
            format!("invalid logical destination {}: {error}", entry.destination),
        )
    })?;
    match entry.kind {
        EntryKind::Directory => match filesystem.stat(&destination) {
            Ok(existing) if existing.kind() == FilesystemEntryKind::Directory => {},
            Ok(_) => {
                return Err(conflict_fs(
                    &destination,
                    "destination kind conflicts with source directory",
                ));
            },
            Err(FilesystemError::NotFound(_)) => {},
            Err(error) => return Err(storage_error(&error)),
        },
        EntryKind::File => match filesystem.stat(&destination) {
            Ok(existing) if existing.kind() == FilesystemEntryKind::File => {

View on GitHub (pinned to affd8760f4)