{"record":{"id":"293f7b9da01593b2","repo":"siyuan-note/siyuan","slug":"bazaarratingratelimited","errorCode":"bazaarRatingRateLimited","errorMessage":"bazaar rating rate limited","messagePattern":"bazaar rating rate limited","errorType":"exception","errorClass":"ErrBazaarRatingRateLimited","httpStatus":null,"severity":"warning","filePath":"kernel/model/bazaar_rating.go","lineNumber":60,"sourceCode":"type bazaarRatingCloudResult[T any] struct {\n\tCode int    `json:\"code\"`\n\tMsg  string `json:\"msg\"`\n\tData T      `json:\"data\"`\n}\n\ntype bazaarPackageUserRatingData struct {\n\tRating int `json:\"rating\"`\n}\n\ntype bazaarPackageSetRatingData struct {\n\tRating          int                   `json:\"rating\"`\n\tRatingAvailable *bool                 `json:\"ratingAvailable\"`\n\tPublicRating    *bazaar.PackageRating `json:\"publicRating\"`\n\tDistribution    []int64               `json:\"distribution\"`\n}\n\n// ErrBazaarRatingRateLimited 表示评分请求受到云端频率限制。\nvar ErrBazaarRatingRateLimited = errors.New(\"bazaar rating rate limited\")\n\n// GetInstalledBazaarPackageRatings 获取指定已安装包的公开评分。\nfunc GetInstalledBazaarPackageRatings(ctx context.Context, pkgType string,\n\tpackageNames []string) (ratings map[string]*bazaar.PackageRating, eligiblePackageNames []string, err error) {\n\tif !isValidBazaarPackageType(pkgType) {\n\t\treturn nil, nil, errors.New(\"invalid package type\")\n\t}\n\n\tinstalledInfos, _, _, err := bazaarRatingInstalledPackageInfos(pkgType)\n\tif nil != err {\n\t\treturn nil, nil, err\n\t}\n\tinstalled := make(map[string]bool, len(installedInfos))\n\tfor _, info := range installedInfos {\n\t\tif \"\" == info.Pkg.InvalidReason {\n\t\t\tinstalled[info.Pkg.Name] = true\n\t\t}\n\t}","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/afa823b6b4e4f183511e0bc0a3be93caa94c7c97/kernel/model/bazaar_rating.go#L42-L78","documentation":"Sentinel error ErrBazaarRatingRateLimited (kernel/model/bazaar_rating.go:60) returned by requestBazaarPackageRating when the cloud server answers an HTTP 429 Too Many Requests. It guards both getBazaarPackageRating and setBazaarPackageRating endpoints; the kernel itself additionally serializes set calls with bazaarRatingSetMu, so a 429 means the per-account/per-IP quota on the cloud side was exceeded (e.g. repeated clicks on the rating dialog), not local concurrency.","triggerScenarios":"Calling model.GetBazaarPackageRating or model.SetBazaarPackageRating repeatedly in a short window: automated scripts iterating all installed packages' ratings, or a UI that re-opens the rating dialog for each star click without debounce, exhausts the cloud quota and receives 429.","commonSituations":"Batch scripts polling ratings; double-submitted rating forms; multiple devices on one account rating simultaneously; retry storms where each failure immediately re-triggers the request.","solutions":["Match the error with errors.Is(err, model.ErrBazaarRatingRateLimited) and stop retrying immediately","Back off (tens of seconds to minutes) before the next rating request; treat rating as an occasional user action, not polled data","Cache rating results client-side so reopening a dialog does not re-request the cloud"],"exampleFix":"// before\nrating, avail, user, err := model.SetBazaarPackageRating(ctx, pkgType, name, 4)\nif err != nil {\n    log.Println(err) // may print repeatedly in a loop\n}\n\n// after\nrating, avail, user, err := model.SetBazaarPackageRating(ctx, pkgType, name, 4)\nif errors.Is(err, model.ErrBazaarRatingRateLimited) {\n    time.Sleep(30 * time.Second) // back off, then let the user retry once\n    return\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":"func isRateLimited(err error) bool {\n    return errors.Is(err, model.ErrBazaarRatingRateLimited)\n}","tryCatchPattern":"err := requestRating(ctx, ...)\nif errors.Is(err, model.ErrBazaarRatingRateLimited) {\n    // exponential backoff: wait >= 30s; abort after N attempts; surface 'try again later' to the user\n}","preventionTips":["Cache rating responses; do not request on every dialog open","Submit rating changes only on explicit user action, never in loops or on page load","Honor 429 with a single delayed retry, not immediate re-sends"],"tags":["marketplace","ratings","rate-limit","http-429","cloud","sentinel-error"],"backgroundTag":"rate-limited","analyzedSha":"afa823b6b4e4f183511e0bc0a3be93caa94c7c97","analyzedAt":"2026-08-18T17:04:10.865Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}