yuliskov/SmartTube · error · IllegalArgumentException

Dates must not be null

Error message

Dates must not be null

What it means

Chatkit uses isSameDay(Date, Date) to place date headers between messages: each message's date is compared with the previous one's, and null dates would only produce a less helpful NPE inside Calendar.setTime, so the method fails fast with IllegalArgumentException. The null almost always originates in your data — IMessage.getCreatedAt() or the previous message's date — not in the formatter.

Source

Thrown at chatkit/src/main/java/com/stfalcon/chatkit/utils/DateFormatter.java:41

public final class DateFormatter {
    private DateFormatter() {
        throw new AssertionError();
    }

    public static String format(Date date, Template template) {
        return format(date, template.get());
    }

    public static String format(Date date, String format) {
        if (date == null) return "";
        return new SimpleDateFormat(format, Locale.getDefault())
                .format(date);
    }

    public static boolean isSameDay(Date date1, Date date2) {
        if (date1 == null || date2 == null) {
            throw new IllegalArgumentException("Dates must not be null");
        }
        Calendar cal1 = Calendar.getInstance();
        cal1.setTime(date1);
        Calendar cal2 = Calendar.getInstance();
        cal2.setTime(date2);
        return isSameDay(cal1, cal2);
    }

    public static boolean isSameDay(Calendar cal1, Calendar cal2) {
        if (cal1 == null || cal2 == null) {
            throw new IllegalArgumentException("Dates must not be null");
        }
        return (cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA) &&
                cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) &&
                cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR));
    }

    public static boolean isSameYear(Date date1, Date date2) {

View on GitHub (pinned to 3de8d90593)

Solutions

  1. Make getCreatedAt() always return a non-null Date, defaulting to new Date() or new Date(0)
  2. Wrap comparisons in a null-safe helper that decides same-day semantics before calling DateFormatter
  3. Fix the upstream parsing that produces the null (format or timezone mismatch)

Example fix

// before
public Date getCreatedAt() { return mDate; } // null when API omits the timestamp

// after
public Date getCreatedAt() { return mDate != null ? mDate : new Date(0); }
Defensive patterns

Strategy: validation

Validate before calling

static boolean isSameDaySafe(@Nullable Date a, @Nullable Date b) {
    if (a == null || b == null) return false; // explicit policy for missing dates
    return DateFormatter.isSameDay(a, b);
}

Type guard

static boolean hasDate(@Nullable IMessage msg) {
    return msg != null && msg.getCreatedAt() != null;
}

Prevention

When it happens

Trigger: A message model whose getCreatedAt() returns null (missing or unparsable backend timestamp, locally appended pending message); a custom date-header flow passing the previous element's null date on the first comparison.

Common situations: API responses where the timestamp field is optional or the format mismatches the parser so the mapped Date stays null; optimistic sends with unset dates; dialogs whose last message payload lacks a date.

Related errors


AI-assisted analysis of yuliskov/SmartTube@3de8d90593 (2026-08-22). Data as JSON: /api/errors/9910a7fcd87e3d63. Report an issue: GitHub.