thanos-io/thanos · error

Given error is not an issue347 error

Error message

Given error is not an issue347 error: %v

What it means

RepairIssue347 only repairs errors whose cause is an Issue347Error (the Prometheus tsdb issue 347 index-corruption error). It type-asserts errors.Cause(issue347Err) to Issue347Error and returns this error when the assertion fails, meaning the caller passed an overlap or other error that is not the specific issue-347 corruption and thus cannot be auto-repaired by this function.

Solutions

  1. Inspect the original error: if it's generic overlap, find the real root cause (duplicate uploads, second compactor) instead of calling RepairIssue347
  2. Only invoke RepairIssue347 when errors.Is/Cause chain contains an Issue347Error (blocks affected by prometheus/tsdb#347)
  3. For non-347 overlaps, delete or no-compact-mark the offending blocks manually
  4. Unwrap correctly: pass the error with its cause chain intact (don't fmt.Errorf without %w)

Example fix

// before
var ie Issue347Error
if !errors.As(err, &ie) { return }
RepairIssue347(ctx, logger, bkt, ctr, err) // panics/error if not issue347
// after
var ie Issue347Error
if errors.As(err, &ie) {
    RepairIssue347(ctx, logger, bkt, ctr, err)
}
Defensive patterns

Strategy: type-guard

Validate before calling

var ie compact.Issue347Error
if !errors.As(err, &ie) {
    // do NOT call RepairIssue347; handle as a generic overlap
    return handleGenericOverlap(err)
}

Type guard

func isIssue347Err(err error) bool {
    var ie compact.Issue347Error
    return errors.As(err, &ie)
}

Try / catch

// Go
var ie compact.Issue347Error
if errors.As(err, &ie) {
    if rerr := compact.RepairIssue347(ctx, logger, bkt, marks, err); rerr != nil {
        logger.Error("issue347 repair failed", "err", rerr)
    }
} else {
    logger.Warn("not repairable as issue347", "err", err)
}

Prevention

When it happens

Trigger: Calling RepairIssue347 with an error whose cause is not an Issue347Error — e.g. a plain 'overlaps found while gathering blocks' error from a different root cause, or a wrapped error from another failure mode.

Common situations: Automation/scripts that blanket-call RepairIssue347 for every overlap error; a compactor configured with repair enabled encountering overlaps not caused by issue 347 (dual compactor, manual uploads); calling the function directly with a wrapped error that lost the Issue347Error cause chain.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at pkg/compact/compact.go:1113

	if include != nil {
		metas = append(metas, include.BlockMeta)
	}

	sort.Slice(metas, func(i, j int) bool {
		return metas[i].MinTime < metas[j].MinTime
	})
	if overlaps := tsdb.OverlappingBlocks(metas); len(overlaps) > 0 {
		return errors.Errorf("overlaps found while gathering blocks. %s", overlaps)
	}
	return nil
}

// RepairIssue347 repairs the https://github.com/prometheus/tsdb/issues/347 issue when having issue347Error.
func RepairIssue347(ctx context.Context, logger log.Logger, bkt objstore.Bucket, blocksMarkedForDeletion prometheus.Counter, issue347Err error) error {
	ie, ok := errors.Cause(issue347Err).(Issue347Error)
	if !ok {
		return errors.Errorf("Given error is not an issue347 error: %v", issue347Err)
	}

	level.Info(logger).Log("msg", "Repairing block broken by https://github.com/prometheus/tsdb/issues/347", "id", ie.id, "err", issue347Err)

	tmpdir, err := os.MkdirTemp("", fmt.Sprintf("repair-issue-347-id-%s-", ie.id))
	if err != nil {
		return err
	}

	defer func() {
		if err := os.RemoveAll(tmpdir); err != nil {
			level.Warn(logger).Log("msg", "failed to remote tmpdir", "err", err, "tmpdir", tmpdir)
		}
	}()

	bdir := filepath.Join(tmpdir, ie.id.String())
	if err := block.Download(ctx, logger, bkt, ie.id, bdir); err != nil {
		return retry(errors.Wrapf(err, "download block %s", ie.id))

View on GitHub (pinned to 35b8b99117)