{"record":{"id":"2b134928f5fca744","repo":"AlistGo/alist","slug":"chunk-part-has-no-readable-link","errorCode":null,"errorMessage":"chunk part has no readable link","messagePattern":"chunk part has no readable link","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"drivers/chunker/util.go","lineNumber":898,"sourceCode":"\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}\n\t\trc, err := rrc.RangeRead(ctx, httpRange)\n\t\tif err != nil {\n\t\t\t_ = rrc.Close()\n\t\t\treturn nil, err\n\t\t}\n\t\treturn utils.NewReadCloser(rc, func() error {\n\t\t\treturn rrc.Close()\n\t\t}), nil\n\tdefault:\n\t\treturn nil, errors.New(\"chunk part has no readable link\")\n\t}\n}\n\nfunc fsList(ctx context.Context, remotePath string, refresh bool) ([]model.Obj, error) {\n\treturn fs.List(ctx, remotePath, &fs.ListArgs{NoLog: true, Refresh: refresh, NoUpdateIndex: true})\n}\n","sourceCodeStart":880,"sourceCodeEnd":905,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/drivers/chunker/util.go#L880-L905","documentation":"openPartRange switches on the model.Link a chunk resolves to: MFile, RangeReadCloser, etc. If the link has none of the supported readable forms (all relevant fields nil), there is no way to obtain bytes for that chunk and the driver returns 'chunk part has no readable link'.","triggerScenarios":"A remote storage driver returning a model.Link with neither MFile nor RangeReadCloser (nor other handled fields) for a chunk file — typically a backend driver bug, an unsupported link type after an API change, or a link produced for an object type the chunker didn't expect. Happens on read of a chunked file stored on that backend.","commonSituations":"Third-party or custom storage drivers that don't populate RangeReadCloser/MFile in Link; alist version mismatch between driver interface expectations; drivers that only support whole-file links when the chunker needs ranges.","solutions":["Identify which underlying storage driver the chunker mounts and update alist — driver Link population bugs are usually fixed in newer releases","If it's your own driver, populate Link.RangeReadCloser (preferred) or MFile for Get/link results so ranged reads work","As a workaround, move the chunker target to a storage type with full range-read support"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Smoke-test the backend driver supports ranged links before chunking onto it\nlink, err := remoteDriver.Link(ctx, \\\"/probe-file\\\", model.LinkArgs{})\nif err != nil { return err }\nif link.MFile == nil && link.RangeReadCloser == nil {\n    return fmt.Errorf(\"backend %s cannot serve ranged reads; unsuitable as chunker target\", driverName)\n}","typeGuard":"func linkSupportsRangeRead(l *model.Link) bool {\n    return l != nil && (l.MFile != nil || l.RangeReadCloser != nil)\n}","tryCatchPattern":"rc, err := openChunk(ctx, p)\nfor attempt := 0; err != nil && strings.Contains(err.Error(), \"no readable link\") && attempt < 2; attempt++ {\n    time.Sleep(time.Second << attempt) // transient link forms may stabilize\n    rc, err = openChunk(ctx, p)\n}","preventionTips":["Keep alist updated — driver Link bugs are fixed in releases","Prefer mature storage drivers (local, s3, webdav) as chunker targets","For custom drivers, always populate RangeReadCloser in Link"],"tags":["chunker","driver","link","backend"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}