thanos-io/thanos · error

iterate bucket for parquet metadata

Error message

iterate bucket for parquet metadata

What it means

Returned when the errgroup waiting on the concurrent bucket iteration for parquet metadata files fails. It wraps the first error from the iter WithReportingBkt iteration callback (e.g. listing errors from the object store).

Solutions

  1. Look at the wrapped inner error to distinguish a listing error from a read error (read errors surface separately via the next wrap)
  2. Check bucket List permissions and endpoint/credentials config
  3. Retry; transient object-store failures typically resolve
  4. Ensure the context is not being canceled prematurely (timeouts, shutdown ordering)
Defensive patterns

Strategy: retry

Try / catch

if err := scanParquetMetadata(ctx); err != nil {
    if errors.Is(err, context.Canceled) { return err }
    return retry.WithBackoff(ctx, scanParquetMetadata, 3)
}

Prevention

When it happens

Trigger: The objstore.Iter (with WithRecursiveIter) over the parquet metadata prefix returns an error while listing objects — bucket API failures, context cancellation, or a wrapped readMigratedBlocksFromParquetMetadata error propagated via the errgroup (the per-file read errors themselves are collected separately).

Common situations: Bucket unavailable or throttled during listing; IAM lacking ListObjects permission; context canceled (shutdown/deadline) mid-iteration; misconfigured bucket endpoint.

Related errors


AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07). Data as JSON: /api/errors/06ddf8be5ed5118b. Report an issue: GitHub.

Appendix: source

Thrown at pkg/block/fetcher.go:1138

	}

	eg.Go(func() error {
		defer close(ch)

		return f.bkt.Iter(ctx, "", func(name string) error {
			if path.Base(name) == parquetMetaFileName {
				select {
				case ch <- name:
				case <-ctx.Done():
					return ctx.Err()
				}
			}
			return nil
		}, objstore.WithRecursiveIter())
	})

	if err := eg.Wait(); err != nil {
		return errors.Wrap(err, "iterate bucket for parquet metadata")
	}

	if len(merrs) > 0 {
		return errors.Wrap(merrs.Err(), "read parquet metadata files")
	}

	// NOTE(GiedriusS): we need to be extra careful here because Parquet converter trims chunks exactly to the day's range.
	// The input to the Parquet converter might not be aligned exactly so we NEED to have some overlap.
	// So, only delete metas if the migrated blocks cover each day *fully*.
	for id := range filterMigratedBlocksByDayCoverage(allMigratedBlocks, metas) {
		delete(metas, id)
		synced.WithLabelValues("parquet-converted").Inc()
	}

	return nil
}

func filterMigratedBlocksByDayCoverage(migratedBlocks map[ulid.ULID]struct{}, metas map[ulid.ULID]*metadata.Meta) map[ulid.ULID]struct{} {

View on GitHub (pinned to 35b8b99117)