{"record":{"id":"47b43c607b0a7a5e","repo":"AlistGo/alist","slug":"open-download-file-failed-w-47b43c","errorCode":null,"errorMessage":"open download file failed: %w","messagePattern":"open download file failed: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"drivers/mega/driver.go","lineNumber":107,"sourceCode":"\n\t\t//down, err := d.c.NewDownload(n.Node)\n\t\t//if err != nil {\n\t\t//\treturn nil, fmt.Errorf(\"open download file failed: %w\", err)\n\t\t//}\n\n\t\tsize := file.GetSize()\n\t\tresultRangeReader := func(ctx context.Context, httpRange http_range.Range) (io.ReadCloser, error) {\n\t\t\tlength := httpRange.Length\n\t\t\tif httpRange.Length >= 0 && httpRange.Start+httpRange.Length >= size {\n\t\t\t\tlength = -1\n\t\t\t}\n\t\t\tvar down *mega.Download\n\t\t\terr := utils.Retry(3, time.Second, func() (err error) {\n\t\t\t\tdown, err = d.c.NewDownload(node.n)\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"open download file failed: %w\", err)\n\t\t\t}\n\t\t\too := &openObject{\n\t\t\t\tctx:  ctx,\n\t\t\t\td:    down,\n\t\t\t\tskip: httpRange.Start,\n\t\t\t}\n\n\t\t\treturn readers.NewLimitedReadCloser(oo, length), nil\n\t\t}\n\t\tresultRangeReadCloser := &model.RangeReadCloser{RangeReader: resultRangeReader}\n\t\tresultLink := &model.Link{\n\t\t\tRangeReadCloser: resultRangeReadCloser,\n\t\t}\n\t\treturn resultLink, nil\n\t}\n\treturn nil, fmt.Errorf(\"unable to convert dir to mega n\")\n}\n","sourceCodeStart":89,"sourceCodeEnd":125,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/drivers/mega/driver.go#L89-L125","documentation":"Inside the Link() range-reader, three retried attempts to open a Mega download (d.c.NewDownload) all failed. This occurs lazily at first byte-read, not at Link creation. NewDownload fails when the node's server-side download slot cannot be established: node removed, API/session problem, or Mega-side capacity issues.","triggerScenarios":"File deleted or moved between Link creation and the first ranged read; Mega session expired by read time; NewDownload consistently failing with a node in a non-downloadable state (e.g. suspended account or taken-down file); transient server errors outlasting the 3x1s retry window.","commonSituations":"Media players issuing Link then seeking much later; long-lived Link objects cached by the frontend; network flaps longer than the 3-second retry budget; files removed upstream while queued.","solutions":["Retry the whole Link (or re-List the parent) — a fresh NewDownload with a current node often succeeds","Check the node still exists via d.c.FS before retrying; if gone, surface not-found instead of retry","Widen the retry window/backoff (e.g. 5 attempts with exponential backoff) for transient Mega errors","Avoid caching RangeReadCloser-producing Links for long periods; fetch Link close to read time"],"exampleFix":"// before\nerr := utils.Retry(3, time.Second, func() (err error) {\n    down, err = d.c.NewDownload(node.n)\n    return err\n})\nif err != nil {\n    return nil, fmt.Errorf(\"open download file failed: %w\", err)\n}\n\n// after\nerr := utils.Retry(5, 2*time.Second, func() (err error) {\n    down, err = d.c.NewDownload(node.n)\n    if err != nil && strings.Contains(err.Error(), \"not found\") {\n        return err // permanent: don't retry\n    }\n    return err\n})\nif err != nil {\n    return nil, fmt.Errorf(\"open download file failed (node %s): %w\", node.n.GetID(), err)\n}","handlingStrategy":"retry","validationCode":"// Validate node before opening a download\nif node.n == nil || node.n.GetType() == mega.FILE && !node.IsFile() {\n    return nil, errs.ObjectNotFound\n}","typeGuard":null,"tryCatchPattern":"// Fresh Link on retryable open failures\nrc, err := openRange(ctx, link)\nif err != nil && strings.Contains(err.Error(), \"open download file failed\") {\n    if fresh, gerr := d.Get(ctx, path); gerr == nil {\n        if newLink, lerr := d.Link(ctx, fresh, args); lerr == nil {\n            rc, err = openRange(ctx, newLink)\n        }\n    }\n}","preventionTips":["Fetch Link close to read time; don't cache long-lived range readers","Verify node existence before retry storms","Use exponential backoff wider than 3x1s for transient Mega errors"],"tags":["mega","download","retry","range-read","go"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}