{"record":{"id":"1b1caf3c2e23ae32","repo":"AlistGo/alist","slug":"the-remote-storage-driver-need-to-be-enhanced-to-s","errorCode":null,"errorMessage":"the remote storage driver need to be enhanced to support encrytion","messagePattern":"the remote storage driver need to be enhanced to support encrytion","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"drivers/crypt/driver.go","lineNumber":255,"sourceCode":"\t\tModified: remoteObj.ModTime(),\n\t\tIsFolder: remoteObj.IsDir(),\n\t}\n\treturn obj, nil\n\t//return nil, errs.ObjectNotFound\n}\n\nfunc (d *Crypt) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) {\n\tdstDirActualPath, err := d.getActualPathForRemote(file.GetPath(), false)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to convert path to remote path: %w\", err)\n\t}\n\tremoteLink, remoteFile, err := op.Link(ctx, d.remoteStorage, dstDirActualPath, args)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif remoteLink.RangeReadCloser == nil && remoteLink.MFile == nil && len(remoteLink.URL) == 0 {\n\t\treturn nil, fmt.Errorf(\"the remote storage driver need to be enhanced to support encrytion\")\n\t}\n\tremoteFileSize := remoteFile.GetSize()\n\tremoteClosers := utils.EmptyClosers()\n\trangeReaderFunc := func(ctx context.Context, underlyingOffset, underlyingLength int64) (io.ReadCloser, error) {\n\t\tlength := underlyingLength\n\t\tif underlyingLength >= 0 && underlyingOffset+underlyingLength >= remoteFileSize {\n\t\t\tlength = -1\n\t\t}\n\t\trrc := remoteLink.RangeReadCloser\n\t\tif len(remoteLink.URL) > 0 {\n\t\t\tvar converted, err = stream.GetRangeReadCloserFromLink(remoteFileSize, remoteLink)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\trrc = converted\n\t\t}\n\t\tif rrc != nil {\n\t\t\tremoteReader, err := rrc.RangeRead(ctx, http_range.Range{Start: underlyingOffset, Length: length})","sourceCodeStart":237,"sourceCodeEnd":273,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/drivers/crypt/driver.go#L237-L273","documentation":"Returned by Crypt.Link when the resolved remote link provides none of the three access mechanisms the crypt reader needs: no RangeReadCloser, no MFile, and no URL. Crypt decryption requires random-access reads (it seeks to encrypted blocks and streams through the cipher), so a remote driver that only returns an empty Link cannot be used for transparent decryption. This is a hard capability gap, not a transient failure.","triggerScenarios":"Downloading a file through the crypt mount where the underlying driver's Link returns an empty *model.Link — e.g. a driver that has not implemented Link fully, returns only header-based links without a RangeReadCloser, or a driver whose link type is unsupported (some proxy/abstract drivers). op.Link succeeded but produced a Link with all three fields empty.","commonSituations":"Using crypt on top of a storage driver that only supports proxy-only or partial link responses; third-party driver plugins not implementing RangeReadCloser or URL; drivers that rely solely on a Header-only link for redirect scenarios where URL is intentionally blank.","solutions":["Use crypt with a well-supported underlying driver (local, Onedrive, GoogleDrive, S3, etc.) whose Link returns a URL or RangeReadCloser","Update AList and the underlying driver to a version that populates Link.URL or Link.RangeReadCloser","If the underlying driver is custom, enhance it to return at least a URL or implement RangeReadCloser","As a workaround, download directly from the underlying mount (unencrypted) instead of through the crypt mount"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Probe capability once: request a Link for a small file on the underlying storage and check\n// that URL, MFile, or RangeReadCloser is populated before mounting crypt on top of it.","typeGuard":"func supportsCryptLink(l *model.Link) bool {\n    return l.RangeReadCloser != nil || l.MFile != nil || len(l.URL) > 0\n}","tryCatchPattern":"if err != nil {\n    if strings.Contains(err.Error(), \"need to be enhanced to support encrytion\") {\n        // permanent capability gap: switch underlying driver, retrying is pointless\n        return fmt.Errorf(\"underlying driver cannot serve range reads for crypt; use a different storage driver\")\n    }\n    return err\n}","preventionTips":["Choose a mature underlying driver (local, S3, GoogleDrive, Onedrive) for crypt mounts","After adding or upgrading any underlying driver, test one crypt download end-to-end","Treat this error as a hard incompatibility — file an issue on the driver rather than retrying"],"tags":["crypt","download","driver-capability","range-read"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}