{"record":{"id":"d04015c3d9fa472a","repo":"AlistGo/alist","slug":"missing-chunk-data","errorCode":null,"errorMessage":"missing chunk data","messagePattern":"missing chunk data","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"drivers/chunker/util.go","lineNumber":870,"sourceCode":"\t\t\tcontinue\n\t\t}\n\t\tlocalStart := int64(0)\n\t\tif req.Start > partStart {\n\t\t\tlocalStart = req.Start - partStart\n\t\t}\n\t\tlocalLength := utils.Min(part.part.Size-localStart, remaining)\n\t\trc, err := d.openPartRange(ctx, part.link, part.part.Size, localStart, localLength)\n\t\tif err != nil {\n\t\t\t_ = closers.Close()\n\t\t\treturn nil, err\n\t\t}\n\t\treaders = append(readers, rc)\n\t\tclosers.Add(rc)\n\t\tremaining -= localLength\n\t}\n\tif remaining > 0 {\n\t\t_ = closers.Close()\n\t\treturn nil, errors.New(\"missing chunk data\")\n\t}\n\treturn utils.NewReadCloser(io.MultiReader(readers...), func() error {\n\t\treturn closers.Close()\n\t}), nil\n}\n\nfunc (d *Chunker) openPartRange(ctx context.Context, link *model.Link, size, offset, length int64) (io.ReadCloser, error) {\n\thttpRange := http_range.Range{Start: offset, Length: length}\n\tswitch {\n\tcase link.MFile != nil:\n\t\treturn io.NopCloser(io.NewSectionReader(link.MFile, offset, length)), nil\n\tcase link.RangeReadCloser != nil:\n\t\treturn link.RangeReadCloser.RangeRead(ctx, httpRange)\n\tcase link.URL != \"\":\n\t\trrc, err := stream.GetRangeReadCloserFromLink(size, link)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}","sourceCodeStart":852,"sourceCodeEnd":888,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/drivers/chunker/util.go#L852-L888","documentation":"While assembling a multi-reader for a chunked file, after iterating all parts listed in metadata the remaining byte count is still > 0: the chunk files present on the remote are collectively smaller than the metadata's declared size. The driver refuses to serve a truncated file and returns 'missing chunk data'.","triggerScenarios":"Opening/reading a chunked file when one or more chunk files are missing (so the part never enters the readers list) or smaller than metadata expects — e.g. someone deleted a chunk, an upload was interrupted, or the remote lost data. Raised from the read path (openPartRange loop) with all opened readers closed via closers.","commonSituations":"Interrupted uploads leaving partial chunk sets; users manually deleting 'duplicate-looking' chunk files on the target storage; backend data loss or incomplete sync; mismatched metadata after re-chunking with a different chunk size.","solutions":["Verify every chunk file named by the pattern exists on the remote and has the expected size; re-upload the original file to regenerate a complete chunk set","If chunks were deleted from the target storage, restore them from backup before retrying","Prevent recurrence: never hand-manage files inside the chunker's target storage, and ensure uploads complete (no forced kills mid-transfer)"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Pre-flight: verify every chunk object exists with expected size before opening\nfor i := 0; i < meta.NChunks; i++ {\n    name := fmt.Sprintf(d.DataNameFormat, base, i+d.StartFrom)\n    obj, err := fs.Get(ctx, path.Join(dir, name))\n    if err != nil || obj.GetSize() < expectedMin(i) {\n        return fmt.Errorf(\"chunk %d missing/short; refusing to read truncated file\", i)\n    }\n}","typeGuard":null,"tryCatchPattern":"rc, err := chunker.Open(ctx, path)\nif err != nil {\n    if strings.Contains(err.Error(), \"missing chunk data\") {\n        // do NOT retry reads; mark file set incomplete and trigger re-upload/restore\n    }\n    return err\n}","preventionTips":["Treat incomplete chunk sets as data loss — restore from source rather than retrying","Never delete chunk files manually on the target storage","Ensure uploads complete; avoid killing the daemon mid-transfer"],"tags":["chunker","data-loss","read","integrity"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}