siyuan-note/siyuan · warning · ErrBazaarRatingRateLimited

bazaarRatingRateLimited

bazaarRatingRateLimited

Error message

bazaar rating rate limited

What it means

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.

Source

Thrown at kernel/model/bazaar_rating.go:60

type bazaarRatingCloudResult[T any] struct {
	Code int    `json:"code"`
	Msg  string `json:"msg"`
	Data T      `json:"data"`
}

type bazaarPackageUserRatingData struct {
	Rating int `json:"rating"`
}

type bazaarPackageSetRatingData struct {
	Rating          int                   `json:"rating"`
	RatingAvailable *bool                 `json:"ratingAvailable"`
	PublicRating    *bazaar.PackageRating `json:"publicRating"`
	Distribution    []int64               `json:"distribution"`
}

// ErrBazaarRatingRateLimited 表示评分请求受到云端频率限制。
var ErrBazaarRatingRateLimited = errors.New("bazaar rating rate limited")

// GetInstalledBazaarPackageRatings 获取指定已安装包的公开评分。
func GetInstalledBazaarPackageRatings(ctx context.Context, pkgType string,
	packageNames []string) (ratings map[string]*bazaar.PackageRating, eligiblePackageNames []string, err error) {
	if !isValidBazaarPackageType(pkgType) {
		return nil, nil, errors.New("invalid package type")
	}

	installedInfos, _, _, err := bazaarRatingInstalledPackageInfos(pkgType)
	if nil != err {
		return nil, nil, err
	}
	installed := make(map[string]bool, len(installedInfos))
	for _, info := range installedInfos {
		if "" == info.Pkg.InvalidReason {
			installed[info.Pkg.Name] = true
		}
	}

View on GitHub (pinned to afa823b6b4)

Solutions

  1. Match the error with errors.Is(err, model.ErrBazaarRatingRateLimited) and stop retrying immediately
  2. Back off (tens of seconds to minutes) before the next rating request; treat rating as an occasional user action, not polled data
  3. Cache rating results client-side so reopening a dialog does not re-request the cloud

Example fix

// before
rating, avail, user, err := model.SetBazaarPackageRating(ctx, pkgType, name, 4)
if err != nil {
    log.Println(err) // may print repeatedly in a loop
}

// after
rating, avail, user, err := model.SetBazaarPackageRating(ctx, pkgType, name, 4)
if errors.Is(err, model.ErrBazaarRatingRateLimited) {
    time.Sleep(30 * time.Second) // back off, then let the user retry once
    return
}
Defensive patterns

Strategy: retry

Type guard

func isRateLimited(err error) bool {
    return errors.Is(err, model.ErrBazaarRatingRateLimited)
}

Try / catch

err := requestRating(ctx, ...)
if errors.Is(err, model.ErrBazaarRatingRateLimited) {
    // exponential backoff: wait >= 30s; abort after N attempts; surface 'try again later' to the user
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of siyuan-note/siyuan@afa823b6b4 (2026-08-18). Data as JSON: /api/errors/293f7b9da01593b2. Report an issue: GitHub.