{"record":{"id":"e2541d89c97f6cbc","repo":"AlistGo/alist","slug":"wukong-upload-candidates-is-empty","errorCode":null,"errorMessage":"wukong upload candidates is empty","messagePattern":"wukong upload candidates is empty","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"drivers/wukong/driver.go","lineNumber":341,"sourceCode":"\text := strings.TrimPrefix(strings.ToLower(filepath.Ext(file.GetName())), \".\")\n\tfileType := detectWukongFileType(file.GetMimetype(), file.GetName())\n\tsize := file.GetSize()\n\tup(5)\n\n\tuploadType := detectUploadType(file.GetMimetype(), file.GetName())\n\tauthToken, err := d.getUploadAuthToken(ctx, uploadType)\n\tif err != nil {\n\t\treturn err\n\t}\n\tup(10)\n\n\tcandidates, err := d.getUploadCandidates(ctx, authToken)\n\tif err != nil {\n\t\treturn err\n\t}\n\tbestHosts := collectCandidateHosts(candidates)\n\tif len(bestHosts) == 0 {\n\t\treturn errors.New(\"wukong upload candidates is empty\")\n\t}\n\tup(20)\n\n\tapplyResp, err := d.applyUploadInner(ctx, authToken, uploadType, size, strings.Join(bestHosts, \",\"))\n\tif err != nil {\n\t\treturn err\n\t}\n\tif len(applyResp.Result.InnerUploadAddress.UploadNodes) == 0 ||\n\t\tlen(applyResp.Result.InnerUploadAddress.UploadNodes[0].StoreInfos) == 0 {\n\t\treturn errors.New(\"wukong apply upload inner returns empty upload node\")\n\t}\n\tnode := applyResp.Result.InnerUploadAddress.UploadNodes[0]\n\tstore := node.StoreInfos[0]\n\tup(30)\n\n\tif size > multipartChunkSize {\n\t\tif err = d.uploadToTOSMultipart(ctx, node.UploadHost, store.StoreURI, store.Auth, getStorageUserID(store.StorageHeader), tempFile, size, up); err != nil {\n\t\t\treturn err","sourceCodeStart":323,"sourceCodeEnd":359,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/drivers/wukong/driver.go#L323-L359","documentation":"Thrown during Wukong upload when the candidate-host discovery step succeeds (getUploadAuthToken and getUploadCandidates returned no transport error) but collectCandidateHosts() yields zero usable hosts. The upload flow needs at least one host to pass into applyUploadInner's \"best_hosts\" parameter; with none, there is no endpoint to apply an upload against.","triggerScenarios":"The wkbrowser/pan.wkbrowser.com candidates endpoint returns an empty, malformed, or all-filtered-out host list — e.g. regional restrictions, server-side experiment flags, or an API version change that renamed the host fields so every candidate fails the host-collection filter.","commonSituations":"Uploading from an IP region the service doesn't provision upload hosts for; the provider changed its upload-broker response schema (driver drift after an app update); intermittent empty responses under load.","solutions":["Retry the upload after a short delay — transient empty candidate lists do occur","Update the wukong driver to the latest version; host-list parsing in collectCandidateHosts may have been fixed for a changed API shape","Inspect the raw candidates response (enable debug logging) to confirm whether the API returned zero hosts or the filter dropped them all","If the region is blocked, upload via a different network or a different storage driver"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"upload candidates is empty\") {\n    time.Sleep(5 * time.Second)\n    err = d.Put(ctx, dstDir, file, up)\n    // give up after 2-3 attempts; empty candidates is usually server-side\n}","preventionTips":["Keep the wukong driver updated for API-shape changes in candidate responses","Retry with backoff: transient empty host lists resolve on their own","Log the raw candidates response when diagnosing persistent failures"],"tags":["wukong","driver","upload","candidates","api-change","server-side"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}