{"record":{"id":"e25e3088ac1e4c4e","repo":"AlistGo/alist","slug":"env-errmsg","errorCode":null,"errorMessage":"env.Errmsg","messagePattern":"env\\.Errmsg","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"drivers/yunpan360/upload.go","lineNumber":639,"sourceCode":"\tif err != nil {\n\t\treturn err\n\t}\n\tif resp.StatusCode >= http.StatusBadRequest {\n\t\treturn fmt.Errorf(\"yunpan upload request failed: status=%d body=%s\", resp.StatusCode, strings.TrimSpace(string(respBody)))\n\t}\n\treturn decodeUploadResp(respBody, out)\n}\n\nfunc decodeUploadResp(body []byte, out interface{}) error {\n\tvar env uploadEnvelope\n\tif err := utils.Json.Unmarshal(body, &env); err != nil {\n\t\treturn err\n\t}\n\tif env.Errno != nil && *env.Errno != 0 {\n\t\tif env.Errmsg == \"\" {\n\t\t\treturn fmt.Errorf(\"yunpan upload request failed: errno=%d\", *env.Errno)\n\t\t}\n\t\treturn errors.New(env.Errmsg)\n\t}\n\tif env.Errno == nil && strings.TrimSpace(env.Errmsg) != \"\" && len(env.Data) > 0 && string(env.Data) == \"[]\" {\n\t\treturn errors.New(env.Errmsg)\n\t}\n\tif out == nil {\n\t\treturn nil\n\t}\n\tif err := utils.Json.Unmarshal(body, out); err != nil {\n\t\tif strings.TrimSpace(env.Errmsg) != \"\" {\n\t\t\treturn errors.New(env.Errmsg)\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n}\n\ntype multipartFile struct {\n\tFieldName   string","sourceCodeStart":621,"sourceCodeEnd":657,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/drivers/yunpan360/upload.go#L621-L657","documentation":"This is decodeUploadResp propagating the 360 upload API's own error message: the response envelope has errno != 0 and a non-empty errmsg, so errors.New(env.Errmsg) returns the server text verbatim (e.g. \"文件名已存在\" or session-expired messages). It is the standard hard-failure path — the server explicitly rejected the upload request.","triggerScenarios":"Any yunpan360 upload request whose JSON response has a non-zero errno with errmsg: duplicate filename, insufficient quota, invalid/expired auth (qid/token), disallowed file type, or rate limiting from the open API.","commonSituations":"Uploading a file that already exists where overwrite isn't permitted; storage quota full; api_key credentials revoked or expired; hammering the upload endpoint and getting throttled.","solutions":["Read the errmsg text — it states the exact server-side rejection reason","For quota: free space on yunpan.360.cn or delete duplicate files","For auth errors: refresh the api_key/session and re-save the storage config","For rate limits: space out concurrent uploads"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"err := d.Put(ctx, dstDir, file, up)\nif err != nil {\n    msg := err.Error()\n    switch {\n    case strings.Contains(msg, \"存在\") || strings.Contains(msg, \"exist\"): // duplicate\n        // rename or enable overwrite strategy\n    case strings.Contains(msg, \"空间\") || strings.Contains(msg, \"space\"): // quota\n        return fmt.Errorf(\"yunpan360 quota exceeded: %w\", err)\n    default:\n        return err\n    }\n}","preventionTips":["Map known errmsg strings (duplicate, quota, auth) to concrete recovery steps","Check quota before large uploads","Keep credentials fresh to avoid auth errmsgs mid-upload","Limit upload concurrency to avoid rate-limit errmsgs"],"tags":["yunpan360","upload","api-error","upstream","propagated"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}