zxing/zxing · warning · GeneratorException

End date cannot be before start date.

Error message

End date cannot be before start date.

What it means

Thrown by CalendarEventGenerator.getFullDayDateFields when both full-day dates are selected but the start date is strictly after the end date (date1.after(date2) is true). A negative-duration event is invalid, so generation is aborted. Client-side (GWT) input validation in the ZXing web generator.

Source

Thrown at zxing.appspot.com/src/main/java/com/google/zxing/web/generator/client/CalendarEventGenerator.java:248

    String descriptionString = description.getText();
    if (descriptionString.isEmpty()) {
      return "";
    }
    if (descriptionString.contains("\n")) {
      throw new GeneratorException(
          "Description should not contain \\n characters.");
    }
    return "DESCRIPTION:" + descriptionString + "\r\n";
  }

  private String getFullDayDateFields() throws GeneratorException {
    Date date1 = datePicker1.getValue();
    Date date2 = datePicker2.getValue();
    if (date1 == null || date2 == null) {
      throw new GeneratorException("Start and end dates must be set.");
    }
    if (date1.after(date2)) {
      throw new GeneratorException("End date cannot be before start date.");
    }
    // Specify end date as +1 day since it's exclusive
    Date date2PlusDay = new Date(date2.getTime() + 24 * 60 * 60 * 1000);
    DateTimeFormat isoFormatter = DateTimeFormat.getFormat("yyyyMMdd");
    return "DTSTART;VALUE=DATE:" + isoFormatter.format(date1) + "\r\n" +
        "DTEND;VALUE=DATE:" + isoFormatter.format(date2PlusDay) + "\r\n";
  }

  private String getDateTimeValues() throws GeneratorException {
    Date date1 = datePicker1.getValue();
    Date date2 = datePicker2.getValue();
    Date time1 = getDateFromTextBox(timePicker1);
    Date time2 = getDateFromTextBox(timePicker2);
    if (date1 == null || date2 == null || time1 == null || time2 == null) {
      throw new GeneratorException("Start and end dates/times must be set.");
    }
    String timezoneDelta = timeZones.getValue(timeZones.getSelectedIndex());
    long diffTimeZone = Long.parseLong(timezoneDelta);

View on GitHub (pinned to 19aa2d8254)

Solutions

  1. Swap or correct the dates so the start is on or before the end.
  2. Allow equal start/end for a single full-day event; pick a later end date for a multi-day event.
  3. Validate order in a change handler and warn the user before they generate.

Example fix

// before
// start = 2026-08-14, end = 2026-08-13 -> date1.after(date2) -> throws

// after
// start = 2026-08-13, end = 2026-08-14
Defensive patterns

Strategy: validation

Validate before calling

Date d1 = datePicker1.getValue();
Date d2 = datePicker2.getValue();
if (d1 != null && d2 != null && d1.after(d2)) {
  // end date precedes start; warn and block generation
}

Type guard

boolean isOrderedDates(Date start, Date end) {
  return start == null || end == null || !start.after(end);
}

Try / catch

try {
  generator.getText();
} catch (GeneratorException e) {
  // tell user the end date must not be before the start date
}

Prevention

When it happens

Trigger: The user selects a start date that is later than the end date (e.g. start Aug 14, end Aug 13) with the full-day option checked.

Common situations: Picking dates out of order; timezone confusion around midnight; swapping start/end inadvertently.

Related errors


AI-assisted analysis of zxing/zxing@19aa2d8254 (2026-08-14). Data as JSON: /api/errors/60edd315dcd347f8. Report an issue: GitHub.