AlistGo/alist · error
no upload server URL returned
Error message
no upload server URL returned
What it means
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).
Source
Thrown at drivers/darkibox/driver.go:240
fileCode := fileCodeFromObjID(obj.GetID())
return d.callAPI(ctx, "/file/delete", map[string]string{
"file_code": fileCode,
}, nil)
}
func (d *Darkibox) Put(ctx context.Context, dstDir model.Obj, file model.FileStreamer, up driver.UpdateProgress) (model.Obj, error) {
folderID := d.RootFolderID
if dstDir.GetID() != "" {
folderID = folderIDFromObjID(dstDir.GetID())
}
// Step 1: Get the upload server URL
var server uploadServerResult
if err := d.callAPI(ctx, "/upload/server", nil, &server); err != nil {
return nil, fmt.Errorf("get upload server failed: %w", err)
}
if server.URL == "" {
return nil, fmt.Errorf("no upload server URL returned")
}
// Step 2: Upload the file to the upload server
reader := driver.NewLimitedUploadStream(ctx, &driver.ReaderUpdatingProgress{
Reader: file,
UpdateProgress: up,
})
res, err := base.RestyClient.R().
SetContext(ctx).
SetMultipartField("file", file.GetName(), "", reader).
SetMultipartFormData(map[string]string{
"key": d.APIKey,
"fld_id": fldIDStr(folderID),
}).
Post(server.URL)
if err != nil {
return nil, fmt.Errorf("upload failed: %w", err)View on GitHub (pinned to 843d9dc814)
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
Example fix
// before
type uploadServerResult struct {
URL string `json:"url"`
}
// after — tolerate casing variants
type uploadServerResult struct {
URL string `json:"url"`
URLAlt string `json:"Url"`
}
// then: if server.URL == "" { server.URL = server.URLAlt } Defensive patterns
Strategy: validation
Validate before calling
var server uploadServerResult
if err := d.callAPI(ctx, "/upload/server", nil, &server); err == nil {
if server.URL == "" {
return nil, errors.New("upload server response missing URL — provider schema may have changed")
}
} Type guard
func hasUploadURL(s uploadServerResult) bool {
return strings.HasPrefix(s.URL, "http")
} Try / catch
if err != nil && strings.Contains(err.Error(), "no upload server URL") {
// dump raw response once at debug level, then fail fast — retrying won't help a schema mismatch
} Prevention
- Validate URL shape (scheme+host) not just non-empty
- Add integration tests pinning the /upload/server schema
- Watch driver updates after provider API changes
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- invalid file size
- file name is empty
- file size cannot be zero
- get upload server failed: %w
- upload failed: %w
AI-assisted analysis of AlistGo/alist@843d9dc814 (2026-08-15).
Data as JSON: /api/errors/78bc042c79204796.
Report an issue: GitHub.