{"record":{"id":"d1dbb64180dd5ff5","repo":"AlistGo/alist","slug":"empty-download-url-d1dbb6","errorCode":null,"errorMessage":"empty download url","messagePattern":"empty download url","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"drivers/guangyapan/driver.go","lineNumber":236,"sourceCode":"\t\treturn nil, errs.NotFile\n\t}\n\tif err := d.ensureAccessToken(ctx); err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar resp downloadResp\n\tif err := d.postAPI(ctx, \"/nd.bizuserres.s/v1/get_res_download_url\", map[string]any{\n\t\t\"fileId\": file.GetID(),\n\t}, &resp); err != nil {\n\t\treturn nil, err\n\t}\n\n\turl := strings.TrimSpace(resp.Data.SignedURL)\n\tif url == \"\" {\n\t\turl = strings.TrimSpace(resp.Data.DownloadURL)\n\t}\n\tif url == \"\" {\n\t\treturn nil, errors.New(\"empty download url\")\n\t}\n\treturn &model.Link{URL: url}, nil\n}\n\nfunc (d *GuangYaPan) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) error {\n\tif err := d.ensureAccessToken(ctx); err != nil {\n\t\treturn err\n\t}\n\n\tname := strings.TrimSpace(dirName)\n\tif name == \"\" {\n\t\treturn errors.New(\"dir name is empty\")\n\t}\n\n\tparentID := parentDir.GetID()\n\n\tvar out createDirResp\n\tif err := d.postAPI(ctx, \"/nd.bizuserres.s/v1/file/create_dir\", map[string]any{","sourceCodeStart":218,"sourceCodeEnd":254,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/drivers/guangyapan/driver.go#L218-L254","documentation":"GuangYaPan's link resolver called /nd.bizuserres.s/v1/get_res_download_url successfully (no HTTP/API error) but both candidate URL fields — Data.SignedURL and Data.DownloadURL — were empty after trimming. Without a URL the driver cannot construct a model.Link, so it fails fast instead of returning a useless link.","triggerScenarios":"Calling the download/link path for a file whose ID the API accepts but for which it returns an empty payload: files still processing, deleted server-side, region-restricted resources, or transient backend hiccups.","commonSituations":"Downloading immediately after upload before the provider finishes processing; file removed in the provider's own app but listing is cached; provider-side incident returning 200 with empty data.","solutions":["Re-list the directory to refresh the file metadata and retry the download","Verify the file still exists and plays/downloads in the provider's official app/website","Retry after a short wait if the file was just uploaded (processing delay)","If persistent, the file ID may be invalid — re-upload or report to the provider"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Re-resolve metadata before downloading\nobj, err := d.get(ctx, path)\nif err != nil { return err }\nif strings.TrimSpace(obj.GetID()) == \"\" { return errs.ObjectNotFound }\nreturn d.Link(ctx, obj, args)","typeGuard":null,"tryCatchPattern":"link, err := d.Link(ctx, file, args)\nif err != nil {\n\tif strings.Contains(err.Error(), \"empty download url\") {\n\t\ttime.Sleep(2 * time.Second) // file may still be processing\n\t\tfresh, _ := d.get(ctx, file.GetPath())\n\t\tif fresh != nil { return d.Link(ctx, fresh, args) }\n\t}\n\treturn err\n}","preventionTips":["Avoid downloading files immediately after upload; let the provider finish processing","Re-list directories before downloads if entries are cached","Fail visibly rather than retrying forever — persistent empty URLs mean the resource is gone"],"tags":["guangyapan","download","api","driver"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}