astrid-runtime/astrid · error
present migration source has absent digest: {}
Error message
present migration source has absent digest: {} What it means
For each ledger component, a present source must carry a real content digest; the sentinel value `"absent"` is reserved for sources that were verified not to exist. This error is thrown when a component claims `source.present == true` while its `source.digest` is still the `"absent"` sentinel — a self-contradictory ledger entry.
Source
Thrown at crates/astrid-kernel/src/legacy_migration_barrier/ledger.rs:633
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),
));
}
if component.destination_proof.is_absent() && component.source.present {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!("invalid destination proof for component {}", component.name),
));View on GitHub (pinned to affd8760f4)
Solutions
- Recompute the real source digest for the component's source path and write it into `source.digest`, keeping `present: true` only if the source actually exists.
- If the source truly does not exist, set `present: false` and `digest: "absent"` instead.
- Regenerate the component entry (and its destination proof) via the library's migration path rather than editing the JSON directly.
- Re-run the migration resume after the fix so all shape invariants are re-validated.
Example fix
// before
{"name": "principal:01H8X:home", "source": {"present": true, "digest": "absent"}}
// after
{"name": "principal:01H8X:home", "source": {"present": true, "digest": "sha256:9f2c..."}} Defensive patterns
Strategy: validation
Validate before calling
// Pre-flight: present sources carry a real digest, absent sources use the sentinel
fn source_digest_consistent(c: &MigrationComponent) -> bool {
if c.source.present { c.source.digest != "absent" } else { c.source.digest == "absent" }
} Prevention
- Set `present` and `digest` together from a single computation of the source identity
- Never flip `present` in JSON without recomputing the digest
- Let the library derive SourceIdentity from the filesystem instead of templating it
- Dry-run validate_ledger_shape on generated ledgers before writing them
When it happens
Trigger: Calling `validate_ledger_shape` (via `write_ledger` or the decode/validate paths) on a `MigrationLedger` where a component has `source: {"present": true, "digest": "absent"}` — typically from hand-assembled JSON or a builder that set `present` without recomputing the digest.
Common situations: Hand-editing `present` from `false` to `true` without updating the digest; a script template filling in `present: true` while leaving the placeholder digest; partially applied migration steps where the digest update was lost.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- unknown migration component name: {name}
- migration component has a non-canonical principal UID: {name
- migration ledger contains duplicate component: {}
- migration ledger components are not canonically sorted
- absent migration source has a digest: {}
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/86b7382eba1fa102.
Report an issue: GitHub.