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
- Reduce PAGE_ENTRY_LIMIT (or split flushes) so each page's canonical JSON stays under MAX_RECEIPT_PAGE_BYTES when pushing entries.
- Shorten source/destination paths in the migration inventory (e.g. migrate a shallower root) so entries serialize smaller.
- Raise MAX_RECEIPT_PAGE_BYTES deliberately if the deployment can afford larger bounded reads, keeping it consistent with read-side validation in read_page.
- 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
- Keep PAGE_ENTRY_LIMIT comfortably below the size that would push a page past MAX_RECEIPT_PAGE_BYTES for your typical path lengths.
- Estimate entry size from source/destination path lengths and flush early when entries look large.
- Warn (or fail fast) in the inventory generator when paths exceed a sane length budget.
- After any change to MAX_RECEIPT_PAGE_BYTES, re-run both writer and reader validation paths.
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
- principal-home migration receipt exceeds
- absent migration source has a digest
- decode migration ledger
- durable capsule disappeared after publish
- durable capsule failed authoritative verification
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)