thanos-io/thanos · error
bucket is nil
Error message
bucket is nil
What it means
NewCachingBucket validates that a non-nil objstore.Bucket is supplied before wrapping it. Passing nil would leave CachingBucket with a nil embedded Bucket that panics on first use, so the constructor fails fast with "bucket is nil".
Solutions
- Check the error from the underlying bucket client constructor before passing the bucket to NewCachingBucket.
- Log/inspect the bucket factory result; ensure the objstore provider (s3/gcs/etc.) config is valid and non-nil.
- In tests, always build a real or in-memory objstore.Bucket (e.g. objstore.NewInMemBucket) rather than passing nil.
- Fail startup early with a clear message when bucket construction yields nil.
Example fix
// before
bkt, _ := objstore.NewClient(ctx, logger, cfg, reg)
cb, err := cache.NewCachingBucket(bkt, cacheCfg, logger, reg)
// after
bkt, err := objstore.NewClient(ctx, logger, cfg, reg)
if err != nil {
return errors.Wrap(err, "build bucket client")
}
cb, err := cache.NewCachingBucket(bkt, cacheCfg, logger, reg) Defensive patterns
Strategy: validation
Validate before calling
if bkt == nil {
return errors.New("underlying bucket client is nil; check bucket config")
}
cb, err := cache.NewCachingBucket(bkt, cacheCfg, logger, reg) Type guard
func bucketReady(b objstore.Bucket) bool { return b != nil } Try / catch
cb, err := cache.NewCachingBucket(bkt, cacheCfg, logger, reg)
if err != nil {
return errors.Wrap(err, "create caching bucket") // includes 'bucket is nil'
} Prevention
- Check every upstream constructor's error before using its result
- Never ignore the error return when building bucket clients
- Build real/in-memory buckets in tests instead of nil
- Fail fast at startup when the bucket is nil
When it happens
Trigger: Calling NewCachingBucket(nil, cfg, logger, reg), typically when a bucket client construction step upstream returned (nil, nil) or a nil bucket was propagated from a factory/config lookup.
Common situations: Misconfigured bucket client YAML silently producing a nil bucket; ignoring an error from an earlier bucket-constructor call; tests wiring a caching bucket without an underlying bucket.
Related errors
- errObjNotFound
- failed to get object attributes
- fetching range [ , ]
- raw resolution must be higher than the minimum block size…
- 5m resolution retention must be higher than the minimum…
AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07).
Data as JSON: /api/errors/658d93231ac7fa50.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/store/cache/caching_bucket.go:58
objstore.Bucket
cfg *cache.CachingBucketConfig
logger log.Logger
requestedGetRangeBytes *prometheus.CounterVec
fetchedGetRangeBytes *prometheus.CounterVec
refetchedGetRangeBytes *prometheus.CounterVec
operationConfigs map[string][]*cache.OperationConfig
operationRequests *prometheus.CounterVec
operationHits *prometheus.CounterVec
}
// NewCachingBucket creates new caching bucket with provided configuration. Configuration should not be
// changed after creating caching bucket.
func NewCachingBucket(b objstore.Bucket, cfg *cache.CachingBucketConfig, logger log.Logger, reg prometheus.Registerer) (*CachingBucket, error) {
if b == nil {
return nil, errors.New("bucket is nil")
}
cb := &CachingBucket{
Bucket: b,
cfg: cfg,
logger: logger,
operationConfigs: map[string][]*cache.OperationConfig{},
requestedGetRangeBytes: promauto.With(reg).NewCounterVec(prometheus.CounterOpts{
Name: "thanos_store_bucket_cache_getrange_requested_bytes_total",
Help: "Total number of bytes requested via GetRange.",
}, []string{"config"}),
fetchedGetRangeBytes: promauto.With(reg).NewCounterVec(prometheus.CounterOpts{
Name: "thanos_store_bucket_cache_getrange_fetched_bytes_total",
Help: "Total number of bytes fetched because of GetRange operation. Data from bucket is then stored to cache.",
}, []string{"origin", "config"}),
refetchedGetRangeBytes: promauto.With(reg).NewCounterVec(prometheus.CounterOpts{View on GitHub (pinned to 35b8b99117)