bitwarden/server · error · BadRequestException

Range too large.

Error message

Range too large.

What it means

ApiHelpers.GetDateRange (used by the events/audit endpoints) defaults a null range to the last 30 days, swaps reversed start/end, then enforces a hard ceiling: the span must not exceed 367 days. A range wider than one year plus two days is rejected as HTTP 400.

Source

Thrown at src/Api/Utilities/ApiHelpers.cs:102

    /// If a time span greater than 367 days is passed will throw BadRequestException.
    /// </remarks>
    public static Tuple<DateTime, DateTime> GetDateRange(DateTime? start, DateTime? end)
    {
        if (!end.HasValue || !start.HasValue)
        {
            end = DateTime.UtcNow.Date.AddDays(1).AddMilliseconds(-1);
            start = DateTime.UtcNow.Date.AddDays(-30);
        }
        else if (start.Value > end.Value)
        {
            var newEnd = start;
            start = end;
            end = newEnd;
        }

        if ((end.Value - start.Value) > TimeSpan.FromDays(367))
        {
            throw new BadRequestException("Range too large.");
        }

        return new Tuple<DateTime, DateTime>(start.Value, end.Value);
    }
}

View on GitHub (pinned to e93b962371)

Solutions

  1. Split the query into multiple paginated calls, each spanning no more than 367 days.
  2. Narrow the date-picker default range to <= 367 days.
  3. If you control the server, confirm 367 days is the intended cap before changing the constant.

Example fix

// before
GET /events?start=2023-01-01&end=2025-01-01
// after (page 1)
GET /events?start=2024-06-01&end=2024-12-01
Defensive patterns

Strategy: validation

Validate before calling

const MAX_RANGE_DAYS = 367;
function clampRange(start, end) {
  if (end - start > MAX_RANGE_DAYS * 86_400_000) {
    throw new Error(`Date range exceeds ${MAX_RANGE_DAYS} days; split the query.`);
  }
  return { start, end };
}

Type guard

function isWithinRangeLimit(start: Date, end: Date): boolean {
  return (end.getTime() - start.getTime()) <= 367 * 86_400_000;
}

Prevention

When it happens

Trigger: A GET /events (or any call site of GetDateRange) with `start` and `end` query parameters more than 367 days apart.

Common situations: Exporting a full audit/event history; a date picker defaulting to 'all time'; a client computing end-minus-start incorrectly (off-by-year); calendar widgets that round to year boundaries.

Related errors


AI-assisted analysis of bitwarden/server@e93b962371 (2026-08-13). Data as JSON: /api/errors/3f9453ed035e08e9. Report an issue: GitHub.