astrid-runtime/astrid · error

invalid receipt destination

Error message

invalid receipt destination {destination}: {error}

What it means

Raised by verify_destinations when a receipt entry's destination cannot be parsed as a FilesystemPath during post-migration verification. Verification reads back all receipt pages and revalidates each destination; a parse failure aborts verification with InvalidData.

Solutions

  1. Validate receipt files before verification and repair or drop invalid entries
  2. Restore receipts from backup if corrupted
  3. Regenerate the migration by clearing receipts and re-running migration
  4. Check the writer version that produced the receipts for a format bug

Example fix

// before: verifying corrupt receipts aborts
verify_destinations(&filesystem, &receipts, &summary)?;
// after: pre-validate receipts
let receipts = load_and_validate_receipts(&receipts_dir)?;
verify_destinations(&filesystem, &receipts, &summary)?;
Defensive patterns

Strategy: validation

Validate before calling

fn receipts_parse(dir: &Path) -> bool {
    load_receipt_pages(dir).map(|pages| pages.iter().all(|p| p.entries.iter().all(|e| FilesystemPath::new(e.destination.clone()).is_ok()))).unwrap_or(false)
}

Type guard

fn valid_receipt_entry(e: &Entry) -> bool { FilesystemPath::new(e.destination.clone()).is_ok() }

Try / catch

match verify_destinations(&fs, &receipts, &summary) {
    Err(e) if e.kind() == io::ErrorKind::InvalidData => restore_receipts_from_backup()?,
    Err(e) => return Err(e),
    Ok(()) => {},
}

Prevention

When it happens

Trigger: Calling migrate_one_principal -> verify_destinations when a stored receipt entry has a destination string FilesystemPath::new rejects — the same class of malformed logical path as [1505] but discovered at verification time.

Common situations: Receipt files corrupted on disk or partially written by a crashed run, receipts written by an incompatible older version, manual editing of receipt JSON.

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/672c9533ee628774. Report an issue: GitHub.

Appendix: source

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

) -> io::Result<()> {
    let filesystem = AstridFilesystem::new(store.content(), StateOwner::Principal(uid));
    let mut summary = InventorySummary::default();
    let mut count = 0_u64;
    for page_number in 0..receipt.page_count.get() {
        let page = read_page(home, uid, page_number)?;
        if page.page != page_number {
            return Err(conflict_path(
                &receipt_path_for_display(uid),
                "receipt page sequence is not canonical",
            ));
        }
        for entry in page.entries {
            summary.update(&entry)?;
            count = count
                .checked_add(1)
                .ok_or_else(|| io::Error::other("receipt entry count overflow"))?;
            let destination = FilesystemPath::new(entry.destination.clone()).map_err(|error| {
                io::Error::new(
                    io::ErrorKind::InvalidData,
                    format!("invalid receipt destination {}: {error}", entry.destination),
                )
            })?;
            match entry.kind {
                EntryKind::Directory => {
                    let actual = filesystem
                        .stat(&destination)
                        .map_err(|error| storage_error(&error))?;
                    if actual.kind() != FilesystemEntryKind::Directory {
                        return Err(conflict_fs(
                            &destination,
                            "receipt destination is not a directory",
                        ));
                    }
                },
                EntryKind::File => verify_file_content(&filesystem, &destination, &entry)?,
            }

View on GitHub (pinned to affd8760f4)