astrid-runtime/astrid · error
migration ledger components are not canonically sorted
Error message
migration ledger components are not canonically sorted
What it means
`validate_ledger_shape` requires the components array to be strictly sorted ascending by component name (`previous >= name` fails). This error is thrown when entries are out of lexicographic order or repeated adjacently, enforcing a canonical byte layout that makes the ledger deterministic and tamper-evident.
Source
Thrown at crates/astrid-kernel/src/legacy_migration_barrier/ledger.rs:626
pub(super) fn validate_ledger_shape(ledger: &MigrationLedger) -> io::Result<()> {
let mut names = std::collections::BTreeSet::new();
let mut previous = None;
for component in &ledger.components {
validate_component_name(&component.name)?;
if !names.insert(component.name.clone()) {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!(
"migration ledger contains duplicate component: {}",
component.name
),
));
}
if previous
.as_ref()
.is_some_and(|previous: &String| previous >= &component.name)
{
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"migration ledger components are not canonically sorted",
));
}
previous = Some(component.name.clone());
if component.source.present && component.source.digest == "absent" {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!(
"present migration source has absent digest: {}",
component.name
),
));
}
if !component.source.present && component.source.digest != "absent" {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!("absent migration source has a digest: {}", component.name),View on GitHub (pinned to affd8760f4)
Solutions
- Sort the components array lexicographically (byte-wise by component name) and ensure strictly unique names, then re-validate.
- Best: rebuild the ledger through the library's `write_ledger`, which emits canonically sorted components.
- If editing by hand, run a JSON-aware sort on the `name` key of the components array and verify with a resume call.
- Fix the external writer to insert components in sorted position instead of appending.
Example fix
// before
"components": [
{"name": "system:cow", ...},
{"name": "principal:01H8X:home", ...},
{"name": "system:state-db", ...}
]
// after
"components": [
{"name": "principal:01H8X:home", ...},
{"name": "system:cow", ...},
{"name": "system:state-db", ...}
] Defensive patterns
Strategy: validation
Validate before calling
// Pre-flight: components strictly sorted ascending by name
fn components_sorted(ledger: &MigrationLedger) -> bool {
ledger.components.windows(2).all(|w| w[0].name < w[1].name)
} Prevention
- Sort components by name before serializing in any external writer
- Insert new components at their sorted position, never append at the end
- Use the library's write_ledger which guarantees canonical ordering
- Combine the sort check with the uniqueness check — both must hold strictly
When it happens
Trigger: Calling `validate_ledger_shape` (via `write_ledger`, `reject_incomplete_layout_v2`, `retire_post_barrier_sources`, `resume_existing_layout`, or the proof-related tests) on a ledger whose components were appended in insertion order rather than sorted by name — e.g. `system:fresh-layout` appearing after `principal:...` entries, or two entries out of order after a manual edit.
Common situations: Hand-merging ledger files and concatenating arrays without sorting; an external tool that appends new components at the end of the array; JSON tools that preserve original order after edits.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- unknown migration component name: {name}
- migration component has a non-canonical principal UID: {name
- migration ledger is not canonical: {}
- migration ledger contains duplicate component: {}
- present migration source has absent digest: {}
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/2cd531f4fe02dd7d.
Report an issue: GitHub.