AI agents

A Repair Pass When a Checksum Mismatches: Find, Fix or Drop

Antonio Evans7 min read

A split diagram: on the left, a source file with a checksum value that has changed; in the middle, a broken link to a derived task; on the right, three paths labeled Fix, Rebuild, Drop, each with a small log entry icon.
Key points

Key points

  1. 1A checksum mismatch on a derived task means the record you are validating no longer describes the bytes you have, so you must first decide whether the source changed on purpose or the stored checksum is wrong.
  2. 2Verify in a fixed order: the source exists, the source's current checksum, the stored checksum against its own record, then whether the derived output matches the recorded input.
  3. 3Repair means recomputing the checksum from the source and regenerating the derived task; dropping means removing the derived task and keeping a provenance record of why.
  4. 4Every outcome needs a structured log row with the old and new checksums, the decision, and the evidence, because provenance is what makes the decision auditable later.

Why a checksum mismatch is a join problem, not a data problem

A checksum is a short proxy for a file's contents: you compute it at the source, compute it again at the target, and compare, and a difference tells you the two are not identical within the algorithm's limits (FAIR Cookbook, creating checksum files). In a rebuild, the checksum is the key that joins a derived task back to the exact source version that produced it. When the key no longer matches, the join breaks, and the derived task is now attached to nothing you can trust.

This is why the instinct to "just regenerate" is dangerous. Regenerating against whatever the source happens to be now silently re-points the derived task at new content while its history still claims the old input. That is a provenance failure: the record of where data came from and under what authority no longer reflects reality, which is exactly what provenance exists to prevent (Snowflake on provenance vs lineage).

Keep the two concepts separate while you work. Lineage answers "where does this derived task flow from and what will break if I change it," which is your impact question. Provenance answers "where did this version come from, who touched it, and can I trust it," which is your audit question (DataHub on lineage vs provenance). A checksum mismatch touches both, so the repair pass must fix the join and preserve the history.

The three-way check before you decide anything

Before choosing repair, rebuild or drop, gather three facts. Do not skip one because another looks obvious.

  1. Does the source still exist at the recorded location, and is it readable?
  2. What is the source's checksum right now, computed with the same algorithm and the same normalization as the stored one?
  3. Does the stored checksum match the checksum recorded in the source's own provenance record (or the manifest that was published with it)?

You now have a comparison. Treat it as a small decision table:

Source existsCurrent checksum = storedStored = source manifestReading
YesYesYesNo real mismatch; your comparison logic or normalization differs. Fix the compare step.
YesNoYesSource content changed since the derived task was built. Decide if the change was expected.
YesNoNoThe stored checksum and the source disagree with the manifest. Suspect corruption in the checksum record or the transport.
Non/an/aSource is gone. The derived task cannot be validated; drop and log.

The first row is the most common false alarm and the cheapest to fix. Checksums only compare meaningfully when both sides use the same algorithm and were computed over the same bytes, so a line-ending change, a re-serialized JSON document, or a different checksum tool will produce a mismatch with no content difference at all (FAIR Cookbook). This mirrors the classic Go modules mismatch, where developers hit checksum mismatch because the local cache or go.sum held a different hash than the freshly downloaded module (Stack Overflow: Go modules checksum mismatch); clearing the cache and regenerating the sum reconciled them because the bytes were never the problem.

Deciding whether the source changed on purpose

If the source's current checksum differs from the stored one but matches the manifest, the source legitimately changed. Now the question is whether that change was authorized. This is an evaluation decision in the plain sense: a structured judgment against criteria tied to a standard, not a guess (Wikipedia: Evaluation).

Use this three-question rule. If all three answers are yes, repair by adopting the new checksum. If any answer is no, stop and escalate rather than silently rebuild.

  • Was the source change committed through the normal path (a signed release, a reviewed commit, an approved upstream update)?
  • Does the source manifest show the new checksum was published after the derived task was built?
  • Does the downstream consumer of the derived task tolerate the change, or does its own contract pin the old version?

In practice, most rebuild systems pin by version, so "the source changed" usually means "a new version exists." The right move in that case is often to rebuild against the new version and keep the old derived task until the swap is verified, not to mutate the existing one. If you want most of this bookkeeping handled for you, a team plan at Quanta Intelligence (https://quantaintelligence.ai/) can host the rebuild and let specialists wire the checksum step into it with you.

Repair versus rebuild versus drop

The short answer compresses to one rule: repair when the content is right and only the checksum is stale; rebuild when the content genuinely changed and a new derived version is wanted; drop when you cannot establish what the content is.

Repair (recompute in place). The derived output is fine, the source is fine, and only the recorded checksum is wrong or was computed with different normalization. Recompute the checksum from the source, update the derived task's recorded input checksum, and re-run validation. This is the same remedy the Go community reaches for when the sum, not the module, is the stale part (Stack Overflow). Repair is cheap but should be rare; frequent repairs mean your checksum pipeline is inconsistent.

Rebuild (regenerate from the new source). The source changed and the change is authorized (see the three-question rule). Regenerate the derived task from scratch against the new version, record both old and new checksums, and gate the swap on a validation check so you never ship a rebuild that also fails.

Drop (remove and log). The source is missing, unreadable, or the manifest and the record disagree in a way you cannot resolve. Delete the derived task, mark it invalid, and keep a provenance row explaining why. Dropping is not failure; it is the correct outcome when trust cannot be established, and it is far safer than feeding an unvalidated task downstream. Storage and serialization choices affect whether bytes are stable across a round trip, which is one reason content can look identical yet hash differently (benchmark of JSON-compatible binary serialization).

The Fedora packaging case shows how subtle this gets: a maintainer hit a checksum mismatch only in the build system, not locally, and the culprit turned out to be how the cache served the file rather than the file itself (Fedora Discussion: checksum mismatch resolved). If the mismatch reproduces on one host but not another, suspect the transport or cache before you suspect the content, the same lesson seen in dependency-mismatch reports (k9s issue 2468).

A log schema for every outcome

Every repair pass needs an append-only record, one row per derived task touched. Provenance is the chain of custody, so the row must capture who decided, what evidence they used, and what changed (Monte Carlo on provenance vs lineage). A workable schema:

{
  "task_id": "derive_invoice_totals_0042",
  "run_id": "rebuild_2026_10_20T14:03Z",
  "source_uri": "s3://bucket/sources/invoices/v7.parquet",
  "algorithm": "sha256",
  "stored_checksum": "9f2c...a1",
  "source_checksum_now": "4b7e...c9",
  "manifest_checksum": "4b7e...c9",
  "decision": "rebuild",
  "reason_code": "source_changed_authorized",
  "evidence": ["manifest_published_after_task_build", "commit_signed"],
  "actor": "[email protected]",
  "decided_at": "2026-10-20T14:05:11Z",
  "old_task_retained_until": "2026-10-27T14:05:11Z"
}

Two details matter more than the field list. First, keep stored_checksum, source_checksum_now and manifest_checksum as three separate fields; collapsing them loses the exact evidence that justified the decision. Second, use an enum of reason_code values (no_real_mismatch, source_changed_authorized, source_changed_unexpected, checksum_corrupt, source_missing, transport_error) so you can count outcomes over time. When a rubric is used to judge outputs, separate, observable criteria make judgments consistent across reviewers (Twine on writing an evaluation rubric); the same holds for reason codes.

Make the decision auditable against a schema, not just free text. The JSON Schema validation vocabulary defines the structural rules you can assert (required fields, allowed enums, types) so a malformed log row fails loudly instead of drifting (JSON Schema validation). If you validate derived outputs against such a schema, watch for a subtle trap: a schema that is validation-equivalent can still change the behavior of an LLM that reads it, because member order can shift outputs even when the contract is identical (study on JSON Schema instruction artifacts).

A worked example with numbers

Suppose you have 5,000 derived invoice-total tasks. A rebuild reports 200 with checksum mismatches, 4 percent of the set.

The three-way check splits them:

  • 150 have a source that changed and a manifest that matches the new checksum, and the change is authorized. Decision: rebuild. These are cheap and mechanical.
  • 30 have a source that changed but no matching manifest entry, or the change was not authorized. Decision: escalate, then rebuild only after approval. Do not auto-adopt.
  • 15 have a source whose current checksum matches the manifest but not the stored value, and the stored value matches an earlier manifest. This is the stale-checksum case. Decision: repair by recomputing and updating the stored input checksum.
  • 5 have a missing or unreadable source. Decision: drop and log source_missing.

That is 150 rebuilds, 15 repairs, 5 drops and 30 escalations. The math matters because it sets expectations: only 5 of 200 mismatches were genuine data loss, and nearly all the rest were the join being out of date rather than data being corrupt. Teams that treat every mismatch as corruption over-rebuild and waste compute; teams that treat every mismatch as stale checksums ship a bad rebuild.

One loop close is worth its effort. If your transport_error count is nonzero, fix the cache or transport before the next rebuild, because that class of mismatch will return. When you need to pull a fresh model or embedding to sanity-check a repaired output, Quanta Inference (https://quantaintelligence.ai/inference) gives you those calls behind one OpenAI-compatible key so you are not stitching providers into the validation step.

FAQ

FAQ

What is the first thing to check when a checksum mismatch appears?

Check that both sides used the same algorithm and normalization before you assume the content changed. A different line ending, a re-serialized document, or a different checksum tool will produce a mismatch with no content difference (FAIR Cookbook). This false-alarm case is common and cheap to fix.

How do I tell a deliberate source change from corruption?

Compare the source's current checksum to the checksum in its published manifest. If the current checksum matches the manifest, the source changed deliberately and the manifest recorded it; if they disagree, suspect corruption or a transport problem (DataHub). Then confirm the change followed the normal approval path before adopting it.

Should I ever delete a derived task that failed validation?

Yes, when the source is missing or unreadable and you cannot establish what the content is. Dropping an unvalidated task is safer than passing it downstream, provided you keep a provenance row that records the decision, the evidence and the actor (Snowflake). Dropping is a logged outcome, not a silent deletion.

Why keep both old and new checksums in the log?

Because the pair is the proof that explains the decision, and a single value cannot show what changed or why. Provenance records the history of modifications and who made them, which is what an auditor needs to reconstruct the decision ([Monte Carlo](https://montecarlo.ai/blog-data-provenance-vs-data-lineage-difference)). Store the stored, current and manifest checksums as separate fields.

Does repairing a checksum count as changing the data?

No, if repair only recomputes and updates the recorded checksum while the derived output is unchanged. That is why the decision table separates repair (stale checksum) from rebuild (new content): repair restores the join without altering the derived result, mirroring the Go modules fix where the hash, not the module, was stale (Stack Overflow).

Sources

Sources

  1. 7. How to create checksum files - FAIR Cookbook
  2. Data Provenance vs. Data Lineage: Differences & AI Use Cases
  3. Data Lineage vs. Data Provenance: What's the Difference? - DataHub
  4. Go modules: checksum mismatch
  5. Evaluation
  6. A Benchmark of JSON-compatible Binary Serialization ...
  7. Trouble Pushing New Release of Package Due to Checksum ...
  8. Dependency checksum mismatch #2468 - derailed/k9s
  9. Data Provenance Vs. Data Lineage: What's The Difference?
  10. How to Write an LLM Evaluation Rubric - Twine Blog
  11. A Vocabulary for Structural Validation of JSON
  12. Testing JSON Schema Instruction Artifacts
About the author

About the author

Antonio Evans
Antonio Evans

Antonio Evans is the founder of Quanta Intelligence and a fractional CTO who builds HIPAA-ready AI systems for health and life-science companies. Before that he was technical co-founder of FriendsEAT for twenty years, CEO of Socialdraft, and a data engineer at IBM. Antonio lives with his dog Santino in Lisbon, Portugal.

All articles