AlistGo/alist · error
task.Errstr
Error message
task.Errstr
What it means
checkCookieAsyncTask polls a 360 async operation (move/recycle return a task id). When the task reaches terminal status 10 with a non-zero Errno that is not tolerated, and the task carries an Errstr, that server message becomes this error (drivers/yunpan360/util.go:831). It means the async operation ultimately failed server-side.
Source
Thrown at drivers/yunpan360/util.go:831
}
}
// Keep prior behavior when the async task is still pending after the probe window.
return nil
}
func checkCookieAsyncTask(task CookieAsyncTask, toleratedErrnos map[int]struct{}) (bool, error) {
if task.Status != 10 {
return false, nil
}
if task.Errno == 0 {
return true, nil
}
if _, ok := toleratedErrnos[task.Errno]; ok {
return true, nil
}
if strings.TrimSpace(task.Errstr) != "" {
return true, errors.New(task.Errstr)
}
if strings.TrimSpace(task.Action) != "" {
return true, fmt.Errorf("yunpan async task %s failed: errno=%d", task.Action, task.Errno)
}
return true, fmt.Errorf("yunpan async task failed: errno=%d", task.Errno)
}
func (d *Yunpan360) openMove(ctx context.Context, srcName, dstPath string) error {
signParams := map[string]string{
"src_name": srcName,
"new_name": dstPath,
}
return d.openPOST(ctx, "File.move", signParams, nil, signParams, nil, true)
}
func (d *Yunpan360) openDelete(ctx context.Context, targetPath string) error {
return d.openPOST(ctx, "File.delete", nil, nil, map[string]string{
"fname": targetPath,View on GitHub (pinned to 843d9dc814)
Solutions
- Re-list both source and destination to confirm current state, then retry the operation if still needed
- Read Errstr/errno — 'file not exists' means re-sync listings; session errors mean refresh the cookie
- For recurring races, serialize move/delete operations so concurrent UI actions don't invalidate tasks
- Retry once after refreshing the cookie if the errno indicates session expiry
Example fix
// before: treat any async error as fatal
if err := d.waitCookieAsyncTask(ctx, resp.Data.TaskID); err != nil { return err }
// after: tolerate benign 'already moved' errnos
if err := d.waitCookieAsyncTask(ctx, resp.Data.TaskID, toleratedErrnos{errnoAlreadyDone: {}}); err != nil { return err } Defensive patterns
Strategy: retry
Type guard
func isAsyncTaskErr(err error) bool { return err != nil && (strings.Contains(err.Error(), "async task")) } Try / catch
err := d.waitCookieAsyncTask(ctx, resp.Data.TaskID)
if err != nil && isTransientAsyncErr(err) {
time.Sleep(backoff)
err = d.waitCookieAsyncTask(ctx, resp.Data.TaskID)
} Prevention
- Pass toleratedErrnos for known-benign codes (e.g. 'already moved')
- Refresh listings after failed async tasks — partial state is common
- Avoid concurrent user mutations while long moves are in flight
When it happens
Trigger: waitCookieAsyncTask polling a /file/move or /file/recycle task whose remote execution failed — e.g. source vanished mid-task, target folder deleted concurrently, quota exceeded, or session revoked while the task ran. Any cookie-mode move/recycle with resp.Data.IsAsync == true can end here.
Common situations: Large folder moves that race with user deletions in the 360 web UI; tasks abandoned across a cookie refresh; partial-failure errors from 360's backend after retries.
Related errors
- baseResp.Errmsg
- yunpan async task %s failed: errno=%d
- yunpan async task failed: errno=%d
- cookie is empty
- download url is empty
AI-assisted analysis of AlistGo/alist@843d9dc814 (2026-08-15).
Data as JSON: /api/errors/126827bf14cb1b00.
Report an issue: GitHub.