material-components/material-components-android · error · IllegalArgumentException
currentPage cannot be after lastPage
Error message
currentPage cannot be after lastPage
What it means
MonthsPagerAdapter validates that the month the date picker opens at (CalendarConstraints.getOpenAt(), the currentPage) does not fall after the last selectable month (getEnd(), lastPage). An openAt beyond end would place the initial page outside the legal paging range, so the constructor throws IllegalArgumentException.
Source
Thrown at lib/java/com/google/android/material/datepicker/MonthsPagerAdapter.java:84
@Nullable private Month visibleMonth;
@KeyboardFocusDirection private int keyboardFocusDirection = POSITION_UNSPECIFIED;
MonthsPagerAdapter(
@NonNull Context context,
DateSelector<?> dateSelector,
@NonNull CalendarConstraints calendarConstraints,
@Nullable DayViewDecorator dayViewDecorator,
OnDayClickListener onDayClickListener,
@Nullable MaterialCalendar.OnMonthNavigationListener onMonthNavigationListener) {
Month firstPage = calendarConstraints.getStart();
Month lastPage = calendarConstraints.getEnd();
Month currentPage = calendarConstraints.getOpenAt();
if (firstPage.compareTo(currentPage) > 0) {
throw new IllegalArgumentException("firstPage cannot be after currentPage");
}
if (currentPage.compareTo(lastPage) > 0) {
throw new IllegalArgumentException("currentPage cannot be after lastPage");
}
int daysHeight = MonthAdapter.MAXIMUM_WEEKS * MaterialCalendar.getDayHeight(context);
int labelHeight =
MaterialDatePicker.isFullscreen(context) ? MaterialCalendar.getDayHeight(context) : 0;
this.itemHeight = daysHeight + labelHeight;
this.calendarConstraints = calendarConstraints;
this.dateSelector = dateSelector;
this.dayViewDecorator = dayViewDecorator;
this.onDayClickListener = onDayClickListener;
this.onMonthNavigationListener = onMonthNavigationListener;
this.visibleMonth = currentPage;
setHasStableIds(true);
}
public static class ViewHolder extends RecyclerView.ViewHolder {
View on GitHub (pinned to ac7e18efee)
Solutions
- Clamp openAt into the range: openAt = Math.max(start, Math.min(end, openAt)) before calling setOpenAt().
- If the picker should open at the latest allowed month, just omit setOpenAt() or set it equal to end.
- Verify setEnd() receives milliseconds and a value >= setStart(); log the three timestamps during development to catch unit mix-ups.
Example fix
// before
new CalendarConstraints.Builder()
.setStart(start)
.setOpenAt(target) // target > end -> crash
.setEnd(end)
.build();
// after
new CalendarConstraints.Builder()
.setStart(start)
.setOpenAt(Math.min(target, end))
.setEnd(end)
.build(); Defensive patterns
Strategy: validation
Validate before calling
long openAtClamped = Math.max(startMillis, Math.min(endMillis, openAtMillis));
CalendarConstraints constraints = new CalendarConstraints.Builder()
.setStart(startMillis).setEnd(endMillis).setOpenAt(openAtClamped).build(); Try / catch
try { pickerBuilder.setCalendarConstraints(constraints).build(); } catch (IllegalArgumentException e) { constraints = new CalendarConstraints.Builder().setStart(start).setEnd(end).build(); /* no openAt */ } Prevention
- Never set openAt later than end; if in doubt omit openAt.
- Write a unit test: for random (start, openAt, end) triples, assert the clamped builder never throws.
- Treat end < start as a config bug and assert it in debug builds.
When it happens
Trigger: CalendarConstraints.Builder().setOpenAt(openMs).setEnd(endMs) with openMs in a Month after endMs (e.g. openAt = December 2026, end = June 2026). Also triggered when end is defaulted to today's month but openAt is set to a future month, or when end/openAt are swapped by mistake.
Common situations: Letting users pick a future 'open at' month while capping end at today; timezone differences pushing a month boundary; refactors that reorder builder calls and accidentally exchange the end and openAt arguments.
Related errors
- firstPage cannot be after currentPage
- start Month cannot be after current Month
- current Month cannot be after end Month
- firstDayOfWeek is not valid
- There must be a keyline marked as focal.
AI-assisted analysis of material-components/material-components-android@ac7e18efee (2026-08-14).
Data as JSON: /api/errors/9eca2a93bd8bd6b4.
Report an issue: GitHub.