kopia/kopia · error

error recovering from

Error message

error recovering from %v

What it means

In the all-packs recovery path of `kopia index recover`, recoverIndexFromSinglePackFile failed for a discovered pack blob during the parallel processing loop. kopia could not read or parse that pack blob into index entries.

Solutions

  1. Re-run recovery — transient read errors usually clear; kopia tracks already-processed blobs so it resumes quickly.
  2. Identify the failing blob from logs and check its integrity in the storage provider (size vs metadata length).
  3. Restore the corrupt pack blob from provider versioning/snapshots, then re-run.
  4. Exclude foreign/stale blobs by ensuring only this repository's data lives under the bucket prefix.
Defensive patterns

Strategy: fallback

Try / catch

if err := c.recoverIndexFromSinglePackFile(ctx, rep, bm.BlobID, bm.Length, processedBlobCount, recoveredContentCount); err != nil {
    log(ctx).Warnf("skipping unrecoverable pack %v: %v", bm.BlobID, err)
    return nil // continue with remaining packs
}

Prevention

When it happens

Trigger: Running `kopia index recover` (no explicit blob IDs) where a discovered blob fails recovery: corrupt/truncated pack blob, blob that matches a pack prefix but is not a valid pack, or transient storage read error while fetching with the blob's metadata length.

Common situations: Recovery after storage corruption, interrupted uploads, or accidental partial deletion; object stores returning inconsistent reads under high concurrency; mixing blobs from an old repository in the same bucket.

Related errors


AI-assisted analysis of kopia/kopia@82495e54b5 (2026-09-07). Data as JSON: /api/errors/4a80a94bd8e6e4c1. Report an issue: GitHub.

Appendix: source

Thrown at cli/command_index_recover.go:177

						if ok {
							log(ctx).Infof("Recovered %v index entries from %v/%v blobs (%.1f %%) %v remaining %v ETA",
								recoveredContentCount.Load(),
								finishedBlobs,
								disc,
								e.PercentComplete,
								e.Remaining,
								formatTimestamp(e.EstimatedEndTime))
						}
					} else {
						log(ctx).Infof("Recovered %v index entries from %v blobs, estimating time remaining... (found %v blobs)",
							recoveredContentCount.Load(),
							finishedBlobs,
							discoveringBlobCount.Load())
					}
				}

				if err := c.recoverIndexFromSinglePackFile(ctx, rep, bm.BlobID, bm.Length, processedBlobCount, recoveredContentCount); err != nil {
					return errors.Wrapf(err, "error recovering from %v", bm.BlobID)
				}
			}

			return nil
		})
	}

	return errors.Wrap(eg.Wait(), "recovering indexes")
}

func (c *commandIndexRecover) recoverIndexFromSinglePackFile(ctx context.Context, rep repo.DirectRepositoryWriter, blobID blob.ID, length int64, processedBlobCount, recoveredContentCount *atomic.Int32) error {
	log(ctx).Debugf("recovering from %v", blobID)

	recovered, err := rep.ContentManager().RecoverIndexFromPackBlob(ctx, blobID, length, c.commit)
	if err != nil {
		if c.ignoreErrors {
			return nil
		}

View on GitHub (pinned to 82495e54b5)