material-components/material-components-android · error · IllegalArgumentException
current Month cannot be after end Month
Error message
current Month cannot be after end Month
What it means
The companion check in CalendarConstraints: when openAt is non-null and openAt.compareTo(end) > 0, the opening month is past the upper bound and the constructor throws IllegalArgumentException. Together with the start check it enforces start <= openAt <= end, preventing a picker that opens outside its own selectable range.
Source
Thrown at lib/java/com/google/android/material/datepicker/CalendarConstraints.java:77
private CalendarConstraints(
@NonNull Month start,
@NonNull Month end,
@NonNull DateValidator validator,
@Nullable Month openAt,
int firstDayOfWeek) {
Objects.requireNonNull(start, "start cannot be null");
Objects.requireNonNull(end, "end cannot be null");
Objects.requireNonNull(validator, "validator cannot be null");
this.start = start;
this.end = end;
this.openAt = openAt;
this.firstDayOfWeek = firstDayOfWeek;
this.validator = validator;
if (openAt != null && start.compareTo(openAt) > 0) {
throw new IllegalArgumentException("start Month cannot be after current Month");
}
if (openAt != null && openAt.compareTo(end) > 0) {
throw new IllegalArgumentException("current Month cannot be after end Month");
}
if (firstDayOfWeek < 0
|| firstDayOfWeek > UtcDates.getUtcCalendar().getMaximum(Calendar.DAY_OF_WEEK)) {
throw new IllegalArgumentException("firstDayOfWeek is not valid");
}
monthSpan = start.monthsUntil(end) + 1;
yearSpan = end.year - start.year + 1;
}
boolean isWithinBounds(long date) {
return start.getDay(1) <= date && date <= end.getDay(end.daysInMonth);
}
/**
* Returns the {@link DateValidator} that determines whether a date can be clicked and selected.
*/
public DateValidator getDateValidator() {
return validator;View on GitHub (pinned to ac7e18efee)
Solutions
- Clamp openAt to the bounds before building the constraints.
- Omit setOpenAt entirely when there is no trustworthy value; the picker picks a default month within bounds.
- Re-validate restored selections against current start/end before feeding them back.
Example fix
// before
val constraints = CalendarConstraints.Builder()
.setEnd(endMonth)
.setOpenAt(Today) // Today > endMonth -> throws
.build()
// after
val openAt = if (todayMonth > endMonth) endMonth else todayMonth
val constraints = CalendarConstraints.Builder()
.setEnd(endMonth)
.setOpenAt(openAt)
.build() Defensive patterns
Strategy: validation
Validate before calling
fun clampOpenAt(openAt: Month?, start: Month, end: Month): Month? = when {
openAt == null -> null
openAt > end -> end
openAt < start -> start
else -> openAt
}
val constraints = CalendarConstraints.Builder()
.setStart(start).setEnd(end).setOpenAt(clampOpenAt(saved, start, end)).build() Prevention
- For pickers that cap dates at 'today', compute openAt from the same cap, not from a stored selection.
- Re-check bounds whenever constraints change between sessions.
- Prefer omitting setOpenAt over guessing a value.
When it happens
Trigger: Builder().setOpenAt(month) with month after setEnd(month); computing openAt from 'today' while end is capped in the past (e.g. birthdate picker with end = today - 18y and openAt defaulting to today); restoring an old selection newer than a tightened end bound.
Common situations: Date pickers with future dates disallowed (end = today) combined with an openAt computed from a previously selected future date; symmetric to the start violation and appears in the same state-restoration flows.
Related errors
- start Month cannot be after current Month
- firstDayOfWeek is not valid
- Only Gregorian calendars are supported.
- There must be a keyline marked as focal.
- No color resources provided for harmonization.
AI-assisted analysis of material-components/material-components-android@ac7e18efee (2026-08-14).
Data as JSON: /api/errors/0c7de5f9a05ed973.
Report an issue: GitHub.