thanos-io/thanos · error

empty external labels are not allowed for Thanos block.

Error message

empty external labels are not allowed for Thanos block.

What it means

When checkExternalLabels is true, upload() refuses to upload a block whose meta.json lacks Thanos external labels. Thanos requires external labels to build unique block IDs across replicas and to route queries; a block without them would be ambiguous in the bucket.

Solutions

  1. Configure external_labels in Prometheus config so meta.json carries Thanos labels
  2. Pass checkExternalLabels=false only if you intentionally accept label-less blocks
  3. Regenerate meta.json with correct thanos.labels via metadata.Meta before upload

Example fix

// before
meta.Thanos.Labels = map[string]string{}
// after
meta.Thanos.Labels = map[string]string{"prometheus": "cluster-a", "replica": "0"}
Defensive patterns

Strategy: validation

Validate before calling

meta, err := metadata.ReadFromDir(bdir)
if err != nil { return err }
if len(meta.Thanos.Labels) == 0 { return errors.New("block has no Thanos external labels") }

Prevention

When it happens

Trigger: Uploading a Prometheus block whose meta.json has an empty meta.Thanos.Labels map while checkExternalLabels=true (the default via block.Upload).

Common situations: Prometheus not configured with external_labels; meta.json written by older/tooling versions that skipped Thanos labels; hand-crafted meta.json files; sidecar/shipper misconfiguration.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at pkg/block/block.go:134

	if !df.IsDir() {
		return errors.Errorf("%s is not a directory", bdir)
	}

	// Verify dir.
	id, err := ulid.Parse(df.Name())
	if err != nil {
		return errors.Wrap(err, "not a block dir")
	}

	meta, err := metadata.ReadFromDir(bdir)
	if err != nil {
		// No meta or broken meta file.
		return errors.Wrap(err, "read meta")
	}

	if checkExternalLabels {
		if len(meta.Thanos.Labels) == 0 {
			return errors.New("empty external labels are not allowed for Thanos block.")
		}
	}

	metaEncoded := strings.Builder{}
	meta.Thanos.Files, err = GatherFileStats(bdir, hf, logger)
	if err != nil {
		return errors.Wrap(err, "gather meta file stats")
	}

	if err := objstore.UploadDir(ctx, logger, bkt, filepath.Join(bdir, ChunksDirname), path.Join(id.String(), ChunksDirname), options...); err != nil {
		return errors.Wrap(err, "upload chunks")
	}

	if err := objstore.UploadFile(ctx, logger, bkt, filepath.Join(bdir, IndexFilename), path.Join(id.String(), IndexFilename)); err != nil {
		return errors.Wrap(err, "upload index")
	}

	meta.Thanos.UploadTime = time.Now().UTC()

View on GitHub (pinned to 35b8b99117)