thanos-io/thanos · error
failed to sync / blocks
Error message
failed to sync %v/%v blocks
What it means
Summary error returned at the end of Sync when at least one upload failed or a corrupted block was detected (uploadErrs > 0 or failedBlocks > 0) and out-of-order uploads are enabled (errors were logged instead of returned immediately). Note the count formatting shows uploadErrs as the first number and len(failedBlocks) as the denominator, which can be misleading; consult the per-block 'shipping failed' log lines for the actual failing ULIDs.
Solutions
- Search sidecar logs for 'shipping failed' and 'corrupted block' entries to find the exact block ULIDs.
- For corrupted blocks, verify the block in the bucket and delete/restore the local copy (Prometheus will re-compact).
- For transient storage errors, wait for the next sync cycle — failed uploads are automatically retried.
- If failures persist, inspect the object store health and increase timeouts/retries in the objstore config.
Example fix
// before // failed to sync 2/1 blocks (misleading counts; check logs) // after // $ kubectl logs thanos-sidecar | grep 'shipping failed' // # identify ULID, then: thanos tools bucket verify --id=<ULID> and repair local data
Defensive patterns
Strategy: retry
Validate before calling
// before relying on the summary, capture per-block results
_, err := shipper.Sync(ctx)
if err != nil && strings.Contains(err.Error(), "failed to sync") {
log.Printf("partial sync; check 'shipping failed' log lines for ULIDs")
} Try / catch
ticker := time.NewTicker(syncInterval)
for range ticker.C {
if _, err := shipper.Sync(ctx); err != nil {
log.Printf("sync incomplete, will retry next tick: %v", err)
}
} Prevention
- Treat this error as retryable — Sync is idempotent
- Grep logs for 'shipping failed' to get real failing ULIDs (counts in the message are misleading)
- Alert on the shipper's uploadFailures/corruptedBlocks metrics rather than log scraping
- Fix persistent object-store issues quickly; retries are cheap but unbounded
When it happens
Trigger: Sync completes its loop with allowOutOfOrderUploads=true and one or more s.upload() calls failed, or blocks were detected as corrupted (missing/invalid segment files) during iteration.
Common situations: Flaky object storage connectivity during a sync cycle; corrupted blocks on disk (e.g. after unclean shutdown or disk errors); persistent upload failures retried every sync interval.
Related errors
AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07).
Data as JSON: /api/errors/246e446ec873350a.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/shipper/shipper.go:450
// No error returned, just log line. This is because we want other blocks to be uploaded even
// though this one failed. It will be retried on second Sync iteration.
level.Error(s.logger).Log("msg", "shipping failed", "block", m.ULID, "err", err)
uploadErrs++
continue
}
meta.Uploaded = append(meta.Uploaded, m.ULID)
uploaded++
s.metrics.uploads.Inc()
}
if err := WriteMetaFile(s.logger, s.metadataFilePath, meta); err != nil {
level.Warn(s.logger).Log("msg", "updating meta file failed", "err", err)
}
failedExecution = false
if uploadErrs > 0 || len(failedBlocks) > 0 {
s.metrics.uploadFailures.Add(float64(uploadErrs))
s.metrics.corruptedBlocks.Add(float64(len(failedBlocks)))
return uploaded, errors.Errorf("failed to sync %v/%v blocks", uploadErrs, len(failedBlocks))
}
if s.uploadCompacted {
s.metrics.uploadedCompacted.Set(1)
} else {
s.metrics.uploadedCompacted.Set(0)
}
return uploaded, nil
}
func (s *Shipper) UploadedBlocks() map[ulid.ULID]struct{} {
meta, err := ReadMetaFile(s.metadataFilePath)
if err != nil {
// NOTE(GiedriusS): Sync() will inform users about any problems.
return nil
}
ret := make(map[ulid.ULID]struct{}, len(meta.Uploaded))View on GitHub (pinned to 35b8b99117)