thanos-io/thanos · error

opening tsdb directory

Error message

opening tsdb directory

What it means

The sidecar failed to open the local TSDB data directory (os.OpenRoot on conf.tsdb.path) when constructing the block shipper. This is a filesystem-level failure and prevents block upload from starting at all.

Solutions

  1. Point --tsdb.path at the actual Prometheus data directory (the one containing wal/ and block dirs).
  2. Ensure the directory exists and the sidecar's user has read access (check mounts in container deployments).
  3. Verify with ls -la <tsdb.path> as the same user the sidecar runs as.
  4. Confirm the Prometheus data volume is mounted before the sidecar starts.

Example fix

# before
sidecar --tsdb.path=data ...
# after
sidecar --tsdb.path=/var/lib/prometheus ...
Defensive patterns

Strategy: validation

Validate before calling

stat, err := os.Stat(tsdbPath)
if err != nil || !stat.IsDir() { return fmt.Errorf("tsdb path %s missing", tsdbPath) }

Try / catch

if err := run(); err != nil {
    if os.IsNotExist(errors.Unwrap(err)) { /* fix --tsdb.path */ }
}

Prevention

When it happens

Trigger: os.OpenRoot(conf.tsdb.path) returns an error: the path given via --tsdb.path does not exist, is not a directory, or the process lacks read permission on it.

Common situations: --tsdb.path typo or default 'data/' used while Prometheus stores data elsewhere; sidecar running in a container without the Prometheus data volume mounted; permission mismatch between Prometheus (different uid) and the sidecar process.

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/458b9dfa6fd9fcea. Report an issue: GitHub.

Appendix: source

Thrown at cmd/thanos/sidecar.go:462

		g.Add(func() error {
			defer runutil.CloseWithLogOnErr(logger, bkt, "bucket client")

			promReadyTimeout := conf.prometheus.readyTimeout
			extLabelsCtx, cancel := context.WithTimeout(ctx, promReadyTimeout)
			defer cancel()

			if err := runutil.Retry(2*time.Second, extLabelsCtx.Done(), func() error {
				if m.Labels().Len() == 0 {
					return errors.New("not uploading as no external labels are configured yet - is Prometheus healthy/reachable?")
				}
				return nil
			}); err != nil {
				return errors.Wrapf(err, "aborting as no external labels found after waiting %s", promReadyTimeout)
			}

			dataDir, err := os.OpenRoot(conf.tsdb.path)
			if err != nil {
				return errors.Wrap(err, "opening tsdb directory")
			}
			defer runutil.CloseWithLogOnErr(logger, dataDir, "tsdb directory")

			s := shipper.New(
				bkt,
				dataDir,
				shipper.WithLogger(logger),
				shipper.WithRegisterer(reg),
				shipper.WithSource(metadata.SidecarSource),
				shipper.WithHashFunc(metadata.HashFunc(conf.shipper.hashFunc)),
				shipper.WithMetaFileName(conf.shipper.metaFileName),
				shipper.WithLabels(m.Labels),
				shipper.WithUploadCompacted(conf.shipper.uploadCompacted),
				shipper.WithAllowOutOfOrderUploads(conf.shipper.allowOutOfOrderUpload),
				shipper.WithSkipCorruptedBlocks(conf.shipper.skipCorruptedBlocks),
				shipper.WithUploadConcurrency(conf.shipper.uploadConcurrency),
			)

View on GitHub (pinned to 35b8b99117)