kopia/kopia · error
error deleting
Error message
error deleting %v
What it means
Wraps a failure from syncDeleteBlob for a specific BLOB during the delete phase of 'repository sync to --delete', annotating it with the BLOB ID. It means the destination storage refused/failure on DeleteBlob for a reason other than the BLOB already being gone (ErrBlobNotFound is tolerated and returns nil).
Solutions
- Inspect the wrapped inner error in debug logs to identify the exact storage failure
- Grant delete permissions on the destination (e.g. s3:DeleteObject) or use credentials that have them
- Check for object-lock/retention/WORM policies on the destination bucket and remove/relax them if sync --delete is intended
- Re-run the sync once the storage issue is resolved
Example fix
// before: IAM policy without delete
{"Effect":"Allow","Action":["s3:ListBucket","s3:GetObject","s3:PutObject"],...}
// after
{"Effect":"Allow","Action":["s3:ListBucket","s3:GetObject","s3:PutObject","s3:DeleteObject"],...} Defensive patterns
Strategy: validation
Validate before calling
// ensure delete permission exists before running sync --delete
out, err := testDeleteAccess(dstStorage, probeBlobID)
if err != nil || !out { return errors.New("destination lacks delete permission; --delete will fail") } Try / catch
if err := runSyncDelete(ctx); err != nil {
if strings.Contains(err.Error(), "error deleting ") {
log.Printf("delete failed: %v — check delete permissions and retention policies", err)
}
return err
} Prevention
- Verify destination credentials include delete permissions before using --delete
- Check for S3 Object Lock/versioning retention that blocks deletions
- Avoid --delete against WORM/read-only destinations
- Test the sync with --dry-run first to preview deletions
When it happens
Trigger: Running 'kopia repository sync to ... --delete' where dst.DeleteBlob(ctx, m.BlobID) returns a non-ErrBlobNotFound error: permissions lacking delete rights, storage returning access-denied, network failure, or object-lock/retention policies blocking deletion.
Common situations: S3 bucket with Object Lock or versioning-based retention preventing deletes; IAM policy with Put but not DeleteObject; read-only credentials on destination; transient cloud errors.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- error deleting blob
- error listing BLOBs in destination repository
- callback failed for
- Cannot specify a 'point-in-time' option when creating a…
- could not get version metadata for blob
AI-assisted analysis of kopia/kopia@82495e54b5 (2026-09-07).
Data as JSON: /api/errors/45652769515c7c0c.
Report an issue: GitHub.
Appendix: source
Thrown at cli/command_repository_sync.go:274
progressMutex.Lock()
if est, ok := tt.Estimate(float64(bytesCopied), float64(totalBytes)); ok {
eta = fmt.Sprintf("%v (%v)", est.Remaining, formatTimestamp(est.EstimatedEndTime))
speed = units.BytesPerSecondsString(est.SpeedPerSecond)
}
c.outputSyncProgress(
fmt.Sprintf(" Copied %v blobs (%v), Speed: %v, ETA: %v",
numBlobs, units.BytesString(bytesCopied), speed, eta))
progressMutex.Unlock()
}
for m := range deleteCh {
log(ctx).Debugf("[%v] Deleting %v (%v bytes)...\n", workerID, m.BlobID, m.Length)
if err := syncDeleteBlob(ctx, m, dst); err != nil {
return errors.Wrapf(err, "error deleting %v", m.BlobID)
}
}
return nil
})
}
if err := eg.Wait(); err != nil {
return errors.Wrap(err, "error copying blobs")
}
return nil
}
func sliceToChannel(ctx context.Context, md []blob.Metadata) chan blob.Metadata {
ch := make(chan blob.Metadata)
go func() {View on GitHub (pinned to 82495e54b5)