astrid-runtime/astrid · error
invalid receipt page number
Error message
invalid receipt page number: {error} What it means
Thrown by page_number when the numeric portion of a receipt page filename fails to parse. The function strips the receipt suffix, splits on the page marker to isolate the number, then parses it; anything non-numeric is rejected. This guards the receipts directory against non-canonical or garbage filenames.
Solutions
- Rename or remove the offending file so the directory contains only canonical page names (uid + marker + numeric page + suffix).
- List the directory and confirm every file's trailing segment is a small non-negative integer; fix the one failing to parse.
- Do not manually manage receipt pages; let migration tooling create them.
- Exclude the receipts directory from editors/sync tools that create temp files.
Example fix
// before receipt-<uid>-page-abc.json // parse fails // after receipt-<uid>-page-0001.json
Defensive patterns
Strategy: validation
Validate before calling
fn page_name_is_canonical(name: &str, uid: &str) -> bool {
name.strip_suffix(RECEIPT_SUFFIX)
.and_then(|s| s.rsplit_once(RECEIPT_PAGE_MARKER))
.map(|(u, n)| u == uid && n.parse::<u32>().is_ok())
.unwrap_or(false)
} Try / catch
match page_number(path) {
Ok(n) => use(n),
Err(e) if e.kind() == io::ErrorKind::InvalidData => {
// non-canonical filename: quarantine/remove the file, then rescan
let _ = fs::remove_file(path);
rescan_receipts()?;
}
Err(e) => return Err(e),
} Prevention
- Never manually create or rename receipt page files.
- Exclude the receipts directory from editors/sync tools that leave temp files.
- Validate directory listings for canonical names before running verification.
- Let migration tooling own the entire receipts directory.
When it happens
Trigger: read_page resolves a filename where the text after the last RECEIPT_PAGE_MARKER (before RECEIPT_SUFFIX) is not a valid integer — letters, empty segment, or a value overflowing the target integer type.
Common situations: A user manually created or renamed page files; editors or sync tools left temp files like page-0001.json.crash partially matching; a filename from a different naming scheme/version is present.
Understand the failure class
Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.
Related errors
- invalid logical destination
- invalid principal-home migration page
- invalid principal-home migration receipt
- legacy path is not a canonical filesystem path
- legacy principal-home source
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/03bcdf4f98351513.
Report an issue: GitHub.
Appendix: source
Thrown at crates/astrid-kernel/src/principal_home_migration/receipts.rs:262
Ok(page)
},
}
}
fn page_number(path: &Path) -> io::Result<u64> {
let name = path
.file_name()
.and_then(|name| name.to_str())
.ok_or_else(|| invalid_source(path, "receipt page name is not UTF-8"))?;
let uid_and_page = name
.strip_prefix(RECEIPT_PREFIX)
.and_then(|name| name.strip_suffix(RECEIPT_SUFFIX))
.ok_or_else(|| invalid_source(path, "receipt page name is not canonical"))?;
let (_, number) = uid_and_page
.rsplit_once(RECEIPT_PAGE_MARKER)
.ok_or_else(|| invalid_source(path, "receipt page name is not canonical"))?;
number.parse().map_err(|error| {
io::Error::new(
io::ErrorKind::InvalidData,
format!("invalid receipt page number: {error}"),
)
})
}
pub(super) fn remove_stale_pages(home: &AstridHome, uid: PrincipalUid) -> io::Result<()> {
let directory = home.migrations_dir();
let prefix = format!("{RECEIPT_PREFIX}{uid}{RECEIPT_PAGE_MARKER}");
for entry in fs::read_dir(directory)? {
let entry = entry?;
let name = entry.file_name();
let Some(name) = name.to_str() else {
continue;
};
if !name.starts_with(&prefix) || !name.ends_with(RECEIPT_SUFFIX) {
continue;
}View on GitHub (pinned to affd8760f4)