AlistGo/alist · error

chunk part has no readable link

Error message

chunk part has no readable link

What it means

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'.

Source

Thrown at drivers/chunker/util.go:898

	case link.MFile != nil:
		return io.NopCloser(io.NewSectionReader(link.MFile, offset, length)), nil
	case link.RangeReadCloser != nil:
		return link.RangeReadCloser.RangeRead(ctx, httpRange)
	case link.URL != "":
		rrc, err := stream.GetRangeReadCloserFromLink(size, link)
		if err != nil {
			return nil, err
		}
		rc, err := rrc.RangeRead(ctx, httpRange)
		if err != nil {
			_ = rrc.Close()
			return nil, err
		}
		return utils.NewReadCloser(rc, func() error {
			return rrc.Close()
		}), nil
	default:
		return nil, errors.New("chunk part has no readable link")
	}
}

func fsList(ctx context.Context, remotePath string, refresh bool) ([]model.Obj, error) {
	return fs.List(ctx, remotePath, &fs.ListArgs{NoLog: true, Refresh: refresh, NoUpdateIndex: true})
}

View on GitHub (pinned to 843d9dc814)

Solutions

  1. Identify which underlying storage driver the chunker mounts and update alist — driver Link population bugs are usually fixed in newer releases
  2. If it's your own driver, populate Link.RangeReadCloser (preferred) or MFile for Get/link results so ranged reads work
  3. As a workaround, move the chunker target to a storage type with full range-read support
Defensive patterns

Strategy: retry

Validate before calling

// Smoke-test the backend driver supports ranged links before chunking onto it
link, err := remoteDriver.Link(ctx, \"/probe-file\", model.LinkArgs{})
if err != nil { return err }
if link.MFile == nil && link.RangeReadCloser == nil {
    return fmt.Errorf("backend %s cannot serve ranged reads; unsuitable as chunker target", driverName)
}

Type guard

func linkSupportsRangeRead(l *model.Link) bool {
    return l != nil && (l.MFile != nil || l.RangeReadCloser != nil)
}

Try / catch

rc, err := openChunk(ctx, p)
for attempt := 0; err != nil && strings.Contains(err.Error(), "no readable link") && attempt < 2; attempt++ {
    time.Sleep(time.Second << attempt) // transient link forms may stabilize
    rc, err = openChunk(ctx, p)
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of AlistGo/alist@843d9dc814 (2026-08-15). Data as JSON: /api/errors/2b134928f5fca744. Report an issue: GitHub.