{"record":{"id":"78bc042c79204796","repo":"AlistGo/alist","slug":"no-upload-server-url-returned","errorCode":null,"errorMessage":"no upload server URL returned","messagePattern":"no upload server URL returned","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"drivers/darkibox/driver.go","lineNumber":240,"sourceCode":"\tfileCode := fileCodeFromObjID(obj.GetID())\n\treturn d.callAPI(ctx, \"/file/delete\", map[string]string{\n\t\t\"file_code\": fileCode,\n\t}, nil)\n}\n\nfunc (d *Darkibox) Put(ctx context.Context, dstDir model.Obj, file model.FileStreamer, up driver.UpdateProgress) (model.Obj, error) {\n\tfolderID := d.RootFolderID\n\tif dstDir.GetID() != \"\" {\n\t\tfolderID = folderIDFromObjID(dstDir.GetID())\n\t}\n\n\t// Step 1: Get the upload server URL\n\tvar server uploadServerResult\n\tif err := d.callAPI(ctx, \"/upload/server\", nil, &server); err != nil {\n\t\treturn nil, fmt.Errorf(\"get upload server failed: %w\", err)\n\t}\n\tif server.URL == \"\" {\n\t\treturn nil, fmt.Errorf(\"no upload server URL returned\")\n\t}\n\n\t// Step 2: Upload the file to the upload server\n\treader := driver.NewLimitedUploadStream(ctx, &driver.ReaderUpdatingProgress{\n\t\tReader:         file,\n\t\tUpdateProgress: up,\n\t})\n\n\tres, err := base.RestyClient.R().\n\t\tSetContext(ctx).\n\t\tSetMultipartField(\"file\", file.GetName(), \"\", reader).\n\t\tSetMultipartFormData(map[string]string{\n\t\t\t\"key\":    d.APIKey,\n\t\t\t\"fld_id\": fldIDStr(folderID),\n\t\t}).\n\t\tPost(server.URL)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"upload failed: %w\", err)","sourceCodeStart":222,"sourceCodeEnd":258,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/drivers/darkibox/driver.go#L222-L258","documentation":"The /upload/server call succeeded at HTTP and provider-status level, but the parsed response contained an empty URL field, so there is nowhere to POST the file. This is a contract violation by the provider (or a schema mismatch where the URL lives under a different JSON key and unmarshalled to empty).","triggerScenarios":"Provider returns 200 with an empty/null url in the result; the JSON field name changed so uploadServerResult.URL never gets populated; result JSON is an unexpected shape (e.g. array instead of object) that silently unmarshals to zero values.","commonSituations":"Provider A/B testing or API version bump changing field casing (Url vs url); regional accounts without upload entitlements returning empty server lists; schema drift after a Darkibox platform update.","solutions":["Dump the raw /upload/server response (curl with the same query params) and compare the JSON keys against uploadServerResult's tags; fix the struct tag if renamed","If the provider genuinely returns empty URL, the account/region may not allow API uploads — verify in the Darkibox dashboard","Retry once; transient empty responses happen during server rotation"],"exampleFix":"// before\ntype uploadServerResult struct {\n\tURL string `json:\"url\"`\n}\n// after — tolerate casing variants\ntype uploadServerResult struct {\n\tURL string `json:\"url\"`\n\tURLAlt string `json:\"Url\"`\n}\n// then: if server.URL == \"\" { server.URL = server.URLAlt }","handlingStrategy":"validation","validationCode":"var server uploadServerResult\nif err := d.callAPI(ctx, \"/upload/server\", nil, &server); err == nil {\n\tif server.URL == \"\" {\n\t\treturn nil, errors.New(\"upload server response missing URL — provider schema may have changed\")\n\t}\n}","typeGuard":"func hasUploadURL(s uploadServerResult) bool {\n\treturn strings.HasPrefix(s.URL, \"http\")\n}","tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"no upload server URL\") {\n\t// dump raw response once at debug level, then fail fast — retrying won't help a schema mismatch\n}","preventionTips":["Validate URL shape (scheme+host) not just non-empty","Add integration tests pinning the /upload/server schema","Watch driver updates after provider API changes"],"tags":["darkibox","upload","schema-drift","validation"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}