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

  1. Sort the components array lexicographically (byte-wise by component name) and ensure strictly unique names, then re-validate.
  2. Best: rebuild the ledger through the library's `write_ledger`, which emits canonically sorted components.
  3. If editing by hand, run a JSON-aware sort on the `name` key of the components array and verify with a resume call.
  4. 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

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


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