AlistGo/alist · error

get upload token failed: empty task id

Error message

get upload token failed: empty task id

What it means

After POST to obtain an upload task the server replied with a success-ish message, but out.Data.TaskID is empty. The upload token exchange (fileSize included in the res map) is useless without a task id — the subsequent OSS-style credential fields (AccessKeyID/SessionToken/EndPoint fallbacks that follow) all belong to a task. The guard aborts before handing back unusable credentials.

Source

Thrown at drivers/guangyapan/driver.go:900

func (d *GuangYaPan) getUploadToken(ctx context.Context, parentID, name string, size int64) (*uploadTokenData, int, error) {
	var out uploadTokenResp
	err := d.postAPI(ctx, "/nd.bizuserres.s/v1/get_res_center_token", map[string]any{
		"capacity": 2,
		"name":     name,
		"parentId": parentID,
		"res": map[string]any{
			"fileSize": size,
		},
	}, &out)
	if err != nil {
		return nil, 0, err
	}
	msg := strings.TrimSpace(out.Msg)
	if msg != "" && !strings.EqualFold(msg, "success") {
		return nil, out.Code, fmt.Errorf("get upload token failed: %s", msg)
	}
	if out.Data.TaskID == "" {
		return nil, out.Code, errors.New("get upload token failed: empty task id")
	}
	if out.Data.AccessKeyID == "" {
		out.Data.AccessKeyID = out.Data.Creds.AccessKeyID
	}
	if out.Data.SecretAccessKey == "" {
		out.Data.SecretAccessKey = out.Data.Creds.SecretAccessKey
	}
	if out.Data.SessionToken == "" {
		out.Data.SessionToken = out.Data.Creds.SessionToken
	}
	if strings.TrimSpace(out.Data.EndPoint) == "" {
		out.Data.EndPoint = strings.TrimSpace(out.Data.FullEndPoint)
	}
	if strings.TrimSpace(out.Data.EndPoint) != "" && !strings.HasPrefix(out.Data.EndPoint, "http://") && !strings.HasPrefix(out.Data.EndPoint, "https://") {
		if strings.TrimSpace(out.Data.FullEndPoint) != "" {
			out.Data.EndPoint = strings.TrimSpace(out.Data.FullEndPoint)
		} else if strings.TrimSpace(out.Data.BucketName) != "" {
			host := strings.TrimSpace(out.Data.EndPoint)

View on GitHub (pinned to 843d9dc814)

Solutions

  1. Log out.Code and the raw response body for the upload-token call to see what the server actually returned
  2. Reject zero-byte uploads before calling getUploadToken; some backends refuse them with this shape
  3. Verify the response struct in types.go matches the current API field names (taskId vs task_id casing via json tags)
  4. Retry once — a transient gateway truncation can produce an empty data object
Defensive patterns

Strategy: validation

Validate before calling

if size <= 0 {
	return nil, 0, errors.New("guangyapan upload requires a positive file size")
}

Try / catch

token, code, err := d.getUploadToken(ctx, name, size)
if err != nil && strings.Contains(err.Error(), "empty task id") {
	// server accepted but created no task: surface size/code for diagnosis
	return fmt.Errorf("upload token rejected (size=%d code=%d): %w", size, code, err)
}

Prevention

When it happens

Trigger: Upload-token endpoint returns msg="success" (or empty) yet omits data.taskId. Seen with fileSize==0 uploads the backend silently rejects, response envelope drift (task id nested elsewhere), or a truncated success response from a rate-limited gateway.

Common situations: Attempting to upload a 0-byte file; provider API version bump renaming taskId; account out of quota so backend returns success-shaped body without creating a task.

Related errors


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