pingcap/tidb · error

invalid backup data file name: '%s'

Error message

invalid backup data file name: '%s'

What it means

Thrown by GetFileRangeKey in BR's restore (restorer.go). BR groups backup data files by stripping the trailing '_{cf}.sst' suffix from the canonical name '{store_id}_{region_id}_{epoch_version}_{key}_{ts}_{cf}.sst' to build checkpoint keys. If strings.LastIndex(f, "_") returns -1 (no underscore at all in the name), the name cannot be a backup data file, so the function panics.

Source

Thrown at br/pkg/restore/restorer.go:417

				}
			}
			return nil
		})
	}
	// Once the parent context canceled and there is no task running in the errgroup,
	// we may break the for loop without error in the errgroup. (Will this happen?)
	// At that time, return the error in the context here.
	return m.ectx.Err()
}

// GetFileRangeKey is used to reduce the checkpoint number, because we combine the write cf/default cf into one restore file group.
// during full restore, so we can reduce the checkpoint number with the common prefix of the file.
func GetFileRangeKey(f string) string {
	// the backup date file pattern is `{store_id}_{region_id}_{epoch_version}_{key}_{ts}_{cf}.sst`
	// so we need to compare without the `_{cf}.sst` suffix
	idx := strings.LastIndex(f, "_")
	if idx < 0 {
		panic(fmt.Sprintf("invalid backup data file name: '%s'", f))
	}

	return f[:idx]
}

type PipelineRestorerWrapper[T any] struct {
	split.PipelineRegionsSplitter
}

// WithSplit processes items using a split strategy within a pipeline.
// It iterates over items, accumulating them until a split condition is met.
// When a split is required, it executes the split operation on the accumulated items.
func (p *PipelineRestorerWrapper[T]) WithSplit(ctx context.Context, i iter.TryNextor[T], strategy split.SplitStrategy[T]) iter.TryNextor[T] {
	return iter.TryMap(
		iter.FilterOut(i, func(item T) bool {
			// Skip items based on the strategy's criteria.
			// Non-skip iterms should be filter out.
			return strategy.ShouldSkip(item)

View on GitHub (pinned to d01f9615c1)

Solutions

  1. Inspect the backup's sst directory (or s3://.../sst/) for files whose names lack underscores and remove the foreign/corrupted files.
  2. Retake or re-download the backup with br/BR untouched so all data files keep the canonical {store_id}_{region_id}_{epoch_version}_{key}_{ts}_{cf}.sst naming.
  3. Verify the backup with 'br backup validate' / restore dry-run before pointing restore at it.
  4. If the file came from BR itself, report a bug with the file listing and backup meta.

Example fix

// before
key := GetFileRangeKey(fileName) // panics on foreign file names

// after: guard before use (caller-side, since GetFileRangeKey is internal)
if !strings.Contains(fileName, "_") || !strings.HasSuffix(fileName, ".sst") {
    return errors.Errorf("skipping non-backup file in sst dir: %s", fileName)
}
key := GetFileRangeKey(fileName)
Defensive patterns

Strategy: validation

Validate before calling

import (
    "regexp"
    "strings"
)

var reBackupSST = regexp.MustCompile(`^\d+_\d+_\d+_.+_.+_\w+\.sst$`)

func isValidBackupDataName(f string) bool {
    return strings.Contains(f, "_") && reBackupSST.MatchString(f)
}

Prevention

When it happens

Trigger: Any code path that calls GetFileRangeKey on a string without an underscore: walking a backup 'sst' directory that contains a foreign file (README, .DS_Store, a renamed or truncated .sst, a marker file), or passing a metadata/schema file name where a data file name is expected.

Common situations: Users copying backups with tools that rename files; cloud storage buckets (S3) where extra objects live under the sst/ prefix; hand-edited or partially uploaded backups; a checkpoint restore re-reading a directory after files were manually added.

Related errors


AI-assisted analysis of pingcap/tidb@d01f9615c1 (2026-08-15). Data as JSON: /api/errors/c9515cd93951f0d1. Report an issue: GitHub.