thanos-io/thanos · error
open dir
Error message
open dir
What it means
This error wraps a failure from s.dir.Open(".") inside blockMetasFromOldest, which opens the shipper's local directory to enumerate block directories. The shipper dir is an afero Fs abstraction over the TSDB dir; if it cannot be opened, no block metas can be listed and Sync/AreAllBlocksUploaded fail.
Solutions
- Verify the shipper/TSDB directory path exists and is readable: ls -ld <dir>; fix the configured path if wrong.
- Fix permissions so the process can open the directory (chown/chmod).
- Check the volume is mounted (df -h, mount output); remount if detached.
- Restart the process after restoring the directory so afero's dir handle is re-established.
Example fix
// before: wrong path configured --prometheus.tsdb.path=/prometheus/data/typo // after: point to the actual TSDB dir --prometheus.tsdb.path=/prometheus
Defensive patterns
Strategy: validation
Validate before calling
info, err := os.Stat(shipperDir)
if os.IsNotExist(err) {
return fmt.Errorf("shipper dir %s does not exist", shipperDir)
}
if err != nil {
return err
}
if !info.IsDir() {
return fmt.Errorf("%s is not a directory", shipperDir)
} Type guard
func dirExistsAndReadable(path string) bool {
info, err := os.Stat(path)
return err == nil && info.IsDir()
} Try / catch
dir, err := s.dir.Open(".")
if err != nil {
if os.IsNotExist(err) {
return nil, nil, errors.Wrapf(err, "open dir: shipper dir missing, check configured path")
}
return nil, nil, errors.Wrap(err, "open dir")
} Prevention
- Validate the --prometheus.tsdb.path flag at startup before syncing.
- Use a StatefulSet/localhost mount so the TSDB path is stable across restarts.
- Check volume mount health in orchestration (no detached PVs).
- Fix directory ownership/permissions before starting the sidecar.
When it happens
Trigger: Calling Shipper.Sync or AreAllBlocksUploaded when the configured shipper directory no longer exists (deleted/renamed), is not accessible due to permissions, or the underlying filesystem is unavailable/unmounted.
Common situations: Misconfigured --prometheus.tsdb.path / shipper dir path pointing to a non-existent location; NFS or cloud volume detach; directory removed by aggressive retention cleanup while the sidecar was running.
Understand the failure class
Background: "open() failed", "failed to open file", "cannot create file" — what a file open error means and how to fix it — this error's family across 42 libraries.
Related errors
AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07).
Data as JSON: /api/errors/92ef69f429608a64.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/shipper/shipper.go:527
meta.Thanos.Source = s.source
meta.Thanos.SegmentFiles = block.GetSegmentFiles(absUpdir)
if err := meta.WriteToDir(s.logger, absUpdir); err != nil {
return errors.Wrap(err, "write meta file")
}
var uploadOptions []objstore.UploadOption
if s.uploadConcurrency > 0 {
uploadOptions = append(uploadOptions, objstore.WithUploadConcurrency(s.uploadConcurrency))
}
return block.Upload(ctx, s.logger, s.bucket, absUpdir, s.hashFunc, uploadOptions...)
}
// blockMetasFromOldest returns the block meta of each block found in dir
// sorted by minTime asc.
func (s *Shipper) blockMetasFromOldest() (metas []*metadata.Meta, failedBlocks []string, _ error) {
dir, err := s.dir.Open(".")
if err != nil {
return nil, nil, errors.Wrap(err, "open dir")
}
defer runutil.CloseWithLogOnErr(s.logger, dir, "shipper dir")
fis, err := dir.ReadDir(-1)
if err != nil {
return nil, nil, errors.Wrap(err, "read dir")
}
names := make([]string, 0, len(fis))
for _, fi := range fis {
names = append(names, fi.Name())
}
for _, n := range names {
if _, ok := block.IsBlockDir(n); !ok {
continue
}
dir := filepath.Join(s.dir.Name(), n)
View on GitHub (pinned to 35b8b99117)