{"record":{"id":"a4283112639d7eb8","repo":"AlistGo/alist","slug":"get-download-url-failed-string-res","errorCode":null,"errorMessage":"get download url failed: {string(res)}","messagePattern":"get download url failed: (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"drivers/aliyundrive_open/driver.go","lineNumber":118,"sourceCode":"\n\treturn objs, err\n}\n\nfunc (d *AliyundriveOpen) link(ctx context.Context, file model.Obj) (*model.Link, error) {\n\tres, err := d.request(ctx, limiterLink, \"/adrive/v1.0/openFile/getDownloadUrl\", http.MethodPost, func(req *resty.Request) {\n\t\treq.SetBody(base.Json{\n\t\t\t\"drive_id\":   d.DriveId,\n\t\t\t\"file_id\":    file.GetID(),\n\t\t\t\"expire_sec\": 14400,\n\t\t})\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\turl := utils.Json.Get(res, \"url\").ToString()\n\tif url == \"\" {\n\t\tif utils.Ext(file.GetName()) != \"livp\" {\n\t\t\treturn nil, errors.New(\"get download url failed: \" + string(res))\n\t\t}\n\t\turl = utils.Json.Get(res, \"streamsUrl\", d.LIVPDownloadFormat).ToString()\n\t}\n\texp := time.Minute\n\treturn &model.Link{\n\t\tURL:        url,\n\t\tExpiration: &exp,\n\t}, nil\n}\n\nfunc (d *AliyundriveOpen) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) {\n\treturn d.link(ctx, file)\n}\n\nfunc (d *AliyundriveOpen) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) (model.Obj, error) {\n\tnowTime, _ := getNowTime()\n\tnewDir := File{CreatedAt: nowTime, UpdatedAt: nowTime}\n\t_, err := d.request(ctx, limiterOther, \"/adrive/v1.0/openFile/create\", http.MethodPost, func(req *resty.Request) {","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/drivers/aliyundrive_open/driver.go#L100-L136","documentation":"Returned by aliyundrive_open's link() when the get_download_url (v2/file/get_download_url) response contains an empty url field. There is one carve-out: .livp files (Apple Live Photos) fall back to streamsUrl in the configured LIVPDownloadFormat; every other extension with an empty url produces this error, appending the raw response body.","triggerScenarios":"Calling Link() on a file whose download URL the Open API refuses to issue: file deleted/moved server-side, drive_id/file_id mismatch, token lacking file scope, rate-limited URL issuance, or a non-livp file type the endpoint returns streamsUrl-only for.","commonSituations":"Cached listings referencing deleted files; wrong DriveId configured (personal vs. backup drive); self-built (自建) app tokens missing permissions; frequent link requests triggering throttling. The error includes the full JSON body, which usually reveals the server's reason code.","solutions":["Read the appended response body — it typically contains the exact server reason (NotFound, PermissionDenied, TooManyRequests) and dictates the fix","Refresh the directory listing and retry on the current file_id — stale IDs from cached listings are the most common cause","Verify DriveId matches the drive that actually owns the file (check the file's drive_id in the listing)","Check the Open Platform app's scopes and the token's permissions; re-authorize if the grant is partial","Throttle Link calls (cache the URL for its expire_sec) to avoid per-file rate limits"],"exampleFix":"// before\nurl := utils.Json.Get(res, \"url\").ToString()\nif url == \"\" {\n    if utils.Ext(file.GetName()) != \"livp\" {\n        return nil, errors.New(\"get download url failed: \" + string(res))\n    }\n    url = utils.Json.Get(res, \"streamsUrl\", d.LIVPDownloadFormat).ToString()\n}\n\n// after — also consult streamsUrl for other media types\nurl := utils.Json.Get(res, \"url\").ToString()\nif url == \"\" {\n    url = utils.Json.Get(res, \"streamsUrl\", d.LIVPDownloadFormat).ToString()\n}\nif url == \"\" {\n    return nil, fmt.Errorf(\"get download url failed for %s: %s\", file.GetID(), string(res))\n}","handlingStrategy":"try-catch","validationCode":"null","typeGuard":"// Go\nfunc isDownloadUrlFail(err error) bool {\n    return err != nil && strings.HasPrefix(err.Error(), \"get download url failed\")\n}","tryCatchPattern":"link, err := d.Link(ctx, file, args)\nif isDownloadUrlFail(err) {\n    // the appended body states the reason:\n    // NotFound -> refresh listing; TooManyRequests -> backoff+retry; permission -> re-auth\n    return nil, err\n}","preventionTips":["Cache issued download URLs until near expire_sec (14400s) instead of re-linking per request","Re-list the directory when links fail on cached files — stale file_ids are the top cause","Match DriveId to the file's owning drive; personal vs backup drives differ"],"tags":["aliyundrive-open","download-url","link","api-response"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}