{"record":{"id":"7792f7b8e7bfe6c3","repo":"AlistGo/alist","slug":"failed-to-get-download-link","errorCode":null,"errorMessage":"failed to get download link","messagePattern":"failed to get download link","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"drivers/lark/driver.go","lineNumber":407,"sourceCode":"\t\t\treturn nil, err\n\t\t}\n\t\t_ = ar.Body.Close()\n\n\t\tif isHTTPAuthFailed(ar.StatusCode) && strings.TrimSpace(c.RefreshToken) != \"\" {\n\t\t\taccessToken, err = c.downloadAccessToken(ctx, true)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treq.Header.Set(\"Authorization\", fmt.Sprintf(\"Bearer %s\", accessToken))\n\t\t\tar, err = http.DefaultClient.Do(req)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\t_ = ar.Body.Close()\n\t\t}\n\n\t\tif ar.StatusCode != http.StatusPartialContent {\n\t\t\treturn nil, errors.New(\"failed to get download link\")\n\t\t}\n\n\t\treturn &model.Link{\n\t\t\tURL: url,\n\t\t\tHeader: http.Header{\n\t\t\t\t\"Authorization\": []string{fmt.Sprintf(\"Bearer %s\", accessToken)},\n\t\t\t},\n\t\t}, nil\n\t}\n\n\treturn nil, errors.New(\"lark download requires web proxy\")\n}\n\nfunc (c *Lark) filePreviewURL(token string) string {\n\tprefix := strings.TrimRight(strings.TrimSpace(c.TenantUrlPrefix), \"/\")\n\tif prefix == \"\" {\n\t\tprefix = \"https://www.feishu.cn\"\n\t}","sourceCodeStart":389,"sourceCodeEnd":425,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/drivers/lark/driver.go#L389-L425","documentation":"In Link() with WebProxy enabled, the driver probes the Feishu download endpoint with a 'Range: bytes=0-1' request and expects 206 Partial Content as proof the URL+Bearer token yield a working download. Any other status after the one retry-with-forced-refresh falls here. It is a link-validation failure: the returned model.Link would be broken, so none is returned.","triggerScenarios":"GET open.feishu.cn/open-apis/drive/v1/files/{token}/download returns non-206 — 403 (no permission on the file), 400 (file type not downloadable, e.g. native docs), 401 twice (both tokens rejected), or a redirect/login HTML page from a non-API gateway.","commonSituations":"User lacks download permission on the shared file; trying to 'download' a Feishu doc/sheet/bitable native file (needs export flow instead); expired download scope on the app token.","solutions":["Check the actual status: temporarily log ar.StatusCode before the guard to identify 401/403/400","For native doc types, use the export flow (createExportTask) instead of direct download","Re-grant app/user permissions (drive:file:download scope) and refresh tokens","Ensure the token used is a user access token with access to that specific file"],"exampleFix":"// before\nif ar.StatusCode != http.StatusPartialContent {\n\treturn nil, errors.New(\"failed to get download link\")\n}\n// after (diagnosable failure)\nif ar.StatusCode != http.StatusPartialContent {\n\treturn nil, fmt.Errorf(\"failed to get download link: probe status=%d\", ar.StatusCode)\n}","handlingStrategy":"try-catch","validationCode":"if !c.WebProxy {\n\treturn nil, errors.New(\"enable web proxy on the lark storage to download files\")\n}","typeGuard":null,"tryCatchPattern":"link, err := c.Link(ctx, file, args)\nif err != nil && err.Error() == \"failed to get download link\" {\n\t// probe failed (401/403/400): check permission and file type, then surface clearly\n\treturn nil, fmt.Errorf(\"feishu refused download for %s (permission or unsupported type): %w\", file.GetPath(), err)\n}","preventionTips":["Check file permissions and downloadable file type before requesting links","For native docs route to the export flow rather than Link()","Patch the guard to include the probe status code so triage needs no reproduction"],"tags":["lark","feishu","download","permissions","driver"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}