astrid-runtime/astrid · error

principal-home migration page exceeds

Error message

principal-home migration page exceeds {MAX_RECEIPT_PAGE_BYTES} bytes

What it means

Migration receipt pages are serialized as canonical JSON and each page must fit within MAX_RECEIPT_PAGE_BYTES so reads stay bounded and DoS-resistant. `PageWriter::flush_page` checks the serialized size before atomically writing the page file; if it exceeds the limit, the write is refused with this InvalidData io::Error. The limit exists because page files are later read back unconditionally and validated byte-for-byte.

Solutions

  1. Reduce PAGE_ENTRY_LIMIT (or split flushes) so each page's canonical JSON stays under MAX_RECEIPT_PAGE_BYTES when pushing entries.
  2. Shorten source/destination paths in the migration inventory (e.g. migrate a shallower root) so entries serialize smaller.
  3. Raise MAX_RECEIPT_PAGE_BYTES deliberately if the deployment can afford larger bounded reads, keeping it consistent with read-side validation in read_page.
  4. Check for duplicate entries being pushed repeatedly (e.g. a loop bug) that inflate the page size.

Example fix

// before
writer.push(entry)?; // many long-path entries buffer past the byte limit before flush
// after
if entries.len() >= PAGE_ENTRY_LIMIT / 2 { writer_flush()?; } // flush more often to keep pages under the byte cap
Defensive patterns

Strategy: try-catch

Validate before calling

// estimate serialized size before flushing
fn page_size_estimate(entries: &[MigrationEntry]) -> usize {
    serde_json::to_vec(&MigrationPage {
        schema: ReceiptSchema::V2,
        uid: test_uid(),
        page: 0,
        entries: entries.to_vec(),
    }).map(|b| b.len() + 1).unwrap_or(usize::MAX)
}
assert!(page_size_estimate(&entries) <= MAX_RECEIPT_PAGE_BYTES);

Try / catch

match writer.finish() {
    Err(e) if e.kind() == io::ErrorKind::InvalidData && e.to_string().contains("page exceeds") => {
        eprintln!("flush pages more frequently or reduce PAGE_ENTRY_LIMIT: {e}");
    },
    Err(e) => return Err(e),
    Ok(page_count) => eprintln!("wrote {page_count} pages"),
}

Prevention

When it happens

Trigger: Calling `PageWriter::push` (or `finish`) when the buffered entries' canonical JSON exceeds MAX_RECEIPT_PAGE_BYTES — i.e. a single flush containing many entries or entries with very long source/destination strings such that the page is too large even though the per-page entry count (PAGE_ENTRY_LIMIT) is respected.

Common situations: Migrating principals with huge home directories where PAGE_ENTRY_LIMIT entries still exceed the byte budget; extremely long file paths in source/destination fields; older data formats with more verbose entry fields.

Understand the failure class

Background: payload too large / request exceeds maximum size: why libraries cap bytes and how to fix oversize payloads — this error's family across 50 libraries.

Related errors


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

Appendix: source

Thrown at crates/astrid-kernel/src/principal_home_migration/receipts.rs:100

    pub(super) fn finish(mut self) -> io::Result<u64> {
        self.flush_page()?;
        Ok(self.page)
    }

    fn flush_page(&mut self) -> io::Result<()> {
        if self.entries.is_empty() {
            return Ok(());
        }
        let page = MigrationPage {
            schema: ReceiptSchema::V2,
            uid: self.uid,
            page: self.page,
            entries: std::mem::take(&mut self.entries),
        };
        let bytes = canonical_json(&page)?;
        if bytes.len() > MAX_RECEIPT_PAGE_BYTES {
            return Err(io::Error::new(
                io::ErrorKind::InvalidData,
                format!("principal-home migration page exceeds {MAX_RECEIPT_PAGE_BYTES} bytes"),
            ));
        }
        astrid_core::platform_fs::atomic_write_private_file(
            &page_path_in(&self.directory, self.uid, self.page),
            &bytes,
        )?;
        self.page = self
            .page
            .checked_add(1)
            .ok_or_else(|| io::Error::other("migration page count overflow"))?;
        Ok(())
    }
}

pub(super) fn validate_receipt_pages(
    home: &AstridHome,

View on GitHub (pinned to affd8760f4)