{"record":{"id":"c9515cd93951f0d1","repo":"pingcap/tidb","slug":"invalid-backup-data-file-name-s","errorCode":null,"errorMessage":"invalid backup data file name: '%s'","messagePattern":"invalid backup data file name: '(.+?)'","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"br/pkg/restore/restorer.go","lineNumber":417,"sourceCode":"\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t})\n\t}\n\t// Once the parent context canceled and there is no task running in the errgroup,\n\t// we may break the for loop without error in the errgroup. (Will this happen?)\n\t// At that time, return the error in the context here.\n\treturn m.ectx.Err()\n}\n\n// GetFileRangeKey is used to reduce the checkpoint number, because we combine the write cf/default cf into one restore file group.\n// during full restore, so we can reduce the checkpoint number with the common prefix of the file.\nfunc GetFileRangeKey(f string) string {\n\t// the backup date file pattern is `{store_id}_{region_id}_{epoch_version}_{key}_{ts}_{cf}.sst`\n\t// so we need to compare without the `_{cf}.sst` suffix\n\tidx := strings.LastIndex(f, \"_\")\n\tif idx < 0 {\n\t\tpanic(fmt.Sprintf(\"invalid backup data file name: '%s'\", f))\n\t}\n\n\treturn f[:idx]\n}\n\ntype PipelineRestorerWrapper[T any] struct {\n\tsplit.PipelineRegionsSplitter\n}\n\n// WithSplit processes items using a split strategy within a pipeline.\n// It iterates over items, accumulating them until a split condition is met.\n// When a split is required, it executes the split operation on the accumulated items.\nfunc (p *PipelineRestorerWrapper[T]) WithSplit(ctx context.Context, i iter.TryNextor[T], strategy split.SplitStrategy[T]) iter.TryNextor[T] {\n\treturn iter.TryMap(\n\t\titer.FilterOut(i, func(item T) bool {\n\t\t\t// Skip items based on the strategy's criteria.\n\t\t\t// Non-skip iterms should be filter out.\n\t\t\treturn strategy.ShouldSkip(item)","sourceCodeStart":399,"sourceCodeEnd":435,"githubUrl":"https://github.com/pingcap/tidb/blob/d01f9615c13e02dfa75922745640dec9d81b802e/br/pkg/restore/restorer.go#L399-L435","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Inspect the backup's sst directory (or s3://.../sst/) for files whose names lack underscores and remove the foreign/corrupted files.","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.","Verify the backup with 'br backup validate' / restore dry-run before pointing restore at it.","If the file came from BR itself, report a bug with the file listing and backup meta."],"exampleFix":"// before\nkey := GetFileRangeKey(fileName) // panics on foreign file names\n\n// after: guard before use (caller-side, since GetFileRangeKey is internal)\nif !strings.Contains(fileName, \"_\") || !strings.HasSuffix(fileName, \".sst\") {\n    return errors.Errorf(\"skipping non-backup file in sst dir: %s\", fileName)\n}\nkey := GetFileRangeKey(fileName)","handlingStrategy":"validation","validationCode":"import (\n    \"regexp\"\n    \"strings\"\n)\n\nvar reBackupSST = regexp.MustCompile(`^\\d+_\\d+_\\d+_.+_.+_\\w+\\.sst$`)\n\nfunc isValidBackupDataName(f string) bool {\n    return strings.Contains(f, \"_\") && reBackupSST.MatchString(f)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never rename, copy piecemeal, or add files inside a backup's sst directory or bucket prefix.","Run 'br backup validate' after taking a backup and before restoring it.","Keep the s3/GCS prefix used for backups dedicated to BR output only."],"tags":["br","restore","filename","validation","panic"],"backgroundTag":null,"analyzedSha":"d01f9615c13e02dfa75922745640dec9d81b802e","analyzedAt":"2026-08-15T12:19:33.324Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}