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

  1. 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
  2. If the provider genuinely returns empty URL, the account/region may not allow API uploads — verify in the Darkibox dashboard
  3. 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

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


AI-assisted analysis of AlistGo/alist@843d9dc814 (2026-08-15). Data as JSON: /api/errors/78bc042c79204796. Report an issue: GitHub.