A partial clone cannot fetch an object
TVO-SYNC-005 — promisor backfill, and why it is not corruption.
Written By Dustin
Last updated About 3 hours ago
If you cloned with --blobless, --blob-limit, --depth, or --no-attachments, your repository is promisor-backed: some objects were legitimately omitted and are fetched lazily from the remote when a read needs them.
A --sparse clone is not promisor-backed — that is a path scope rather than a content filter, and it cannot raise this code. If a path is simply outside your cone, widen it with tovio sparse add <dir>.
TVO-SYNC-005 means one of those lazy fetches failed — either the promisor was unreachable, or it answered and does not have the object (withheld or pruned upstream). The read fails closed rather than returning empty or partial bytes.
This is not corruption
A promisor is trusted for availability only, never for content — a backfilled object is re-hashed on receipt like everything else. So its failure is a recoverable sync error and nothing local is lost. The neighbouring cases are deliberately different codes:
- A byte or hash mismatch on a backfilled object is corruption (
TVO-STORE-001), because a promisor can never substitute content. - A missing object in a complete clone is hard local corruption, never a backfill attempt.
The fixes, in order
tovio remote show <name>tovio fetch --complete- Check the remote is reachable and retry. If the promisor was simply down, that is the whole problem.
- Fatten the clone with
tovio fetch --complete, which backfills everything and takes the repository out of promisor mode. Use--deepen <n>instead if the gap is history rather than content. - Or narrow what you touch to what is already local.
Operations that refuse up front
Some operations need the full object closure and will refuse immediately on a promisor-backed clone rather than discover the problem halfway through — tovio git export is the main one. That is deliberate: an honest "fatten first" beats stalling mid-export, or implicitly downloading the whole repository as a side effect. Run tovio fetch --complete first.
Deciding whether to stay partial
Content-filtered clones are a real speed win on large repositories, and the cost is exactly this: reads depend on the remote. If you work offline often, or run exports, a complete clone is the better trade. A sparse clone does not carry that cost, because everything inside your cone is genuinely local.
Reporting it
The code, which filter you cloned with, and whether the remote was reachable. Not the object address, the path, or the repo id.