dotnet/yarp · error · Exception

rate: Wait(count={count}) exceeds limiter's burst {burst}

Error message

rate: Wait(count={count}) exceeds limiter's burst {burst}

What it means

Thrown by the rate Limiter (a Go-style time/rate port) when WaitAsync is called with a count larger than the limiter's configured burst capacity, and the limit is not Limit.Max (unlimited). This mirrors Go's rate limiter semantics: a single reservation larger than burst can never be satisfied and is rejected immediately rather than blocking forever.

Source

Thrown at src/Kubernetes.Controller/Rate/Limiter.cs:156

    /// </summary>
    /// <param name="count">The count.</param>
    /// <param name="cancellationToken">The cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
    /// <exception cref="Exception">rate: Wait(count={count}) exceeds limiter's burst {burst}.</exception>
    /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
    public async Task WaitAsync(int count, CancellationToken cancellationToken)
    {
        // https://github.com/golang/time/blob/master/rate/rate.go#L226
        int burst = default;
        Limit limit = default;
        lock (_sync)
        {
            burst = _burst;
            limit = _limit;
        }

        if (count > burst && limit != Limit.Max)
        {
            throw new Exception($"rate: Wait(count={count}) exceeds limiter's burst {burst}");
        }

        // Check if ctx is already cancelled
        cancellationToken.ThrowIfCancellationRequested();

        // Determine wait limit
        var waitLimit = limit.DurationFromTokens(count);

        while (true)
        {
            var now = _timeProvider.GetUtcNow();
            var r = ReserveImpl(now, count, waitLimit);
            if (r.Ok)
            {
                var delay = r.DelayFrom(now);
                if (delay > TimeSpan.Zero)
                {
                    await Task.Delay(delay, cancellationToken).ConfigureAwait(false);

View on GitHub (pinned to bd11867bee)

Solutions

  1. Reduce the count argument to be within the configured burst capacity.
  2. Increase the burst parameter when constructing the Limiter (e.g., new Limiter(limit, burst: largerValue)).
  3. If large batches are expected, use Limit.Max for an uncapped limiter or split the wait into smaller counts.
  4. Check ReserveN().OK() before waiting to detect the over-burst condition without throwing.

Example fix

// before
var limiter = new Limiter(Limit.PerSecond(10), burst: 5);
await limiter.WaitAsync(count: 8, ct); // throws
// after
var limiter = new Limiter(Limit.PerSecond(10), burst: 10);
await limiter.WaitAsync(count: 8, ct);
Defensive patterns

Strategy: validation

Validate before calling

if (count > burst && limit != Limit.Max)
{
    throw new ArgumentOutOfRangeException(nameof(count), $"count {count} exceeds burst {burst}");
}
await limiter.WaitAsync(count, ct);

Type guard

static bool IsWithinBurst(Limiter lim, int count) => count <= lim.Burst;

Try / catch

try { await limiter.WaitAsync(count, ct); }
catch (Exception ex) when (ex.Message.Contains("exceeds limiter's burst"))
{ /* reduce count or increase burst, then retry */ }

Prevention

When it happens

Trigger: Calling limiter.WaitAsync(count, ct) where count exceeds the burst value passed to the Limiter constructor. The check fails fast because no amount of waiting can accumulate enough tokens past the burst ceiling.

Common situations: Passing a batch size larger than the configured burst. Raising a batch count without proportionally raising burst. Default burst too small for the workload's reservation size.

Related errors


AI-assisted analysis of dotnet/yarp@bd11867bee (2026-08-13). Data as JSON: /api/errors/9bc0410d159788e7. Report an issue: GitHub.