louislam/uptime-kuma · error · Error

Invalid start date

Error message

Invalid start date

What it means

Maintenance.jsonToBean parses obj.dateRange[0] with `new Date(...)` and throws if the result is NaN (unparseable date string) or has a year > 9999 (out-of-range per the storage schema). This guards the start_date column before it is written; the same check on dateRange[1] produces the sibling 'Invalid end date' error.

Source

Thrown at server/model/maintenance.js:161

     * @param {object} obj Data to fill bean with
     * @returns {Promise<Bean>} Filled bean
     */
    static async jsonToBean(bean, obj) {
        if (obj.id) {
            bean.id = obj.id;
        }

        bean.title = obj.title;
        bean.description = obj.description;
        bean.strategy = obj.strategy;
        bean.interval_day = obj.intervalDay;
        bean.timezone = obj.timezoneOption;
        bean.active = obj.active;

        if (obj.dateRange[0]) {
            const parsedDate = new Date(obj.dateRange[0]);
            if (isNaN(parsedDate.getTime()) || parsedDate.getFullYear() > 9999) {
                throw new Error("Invalid start date");
            }

            bean.start_date = obj.dateRange[0];
        } else {
            bean.start_date = null;
        }

        if (obj.dateRange[1]) {
            const parsedDate = new Date(obj.dateRange[1]);
            if (isNaN(parsedDate.getTime()) || parsedDate.getFullYear() > 9999) {
                throw new Error("Invalid end date");
            }

            bean.end_date = obj.dateRange[1];
        } else {
            bean.end_date = null;
        }

View on GitHub (pinned to 6b5ea01557)

Solutions

  1. Send dateRange[0] as a valid ISO 8601 string (e.g. '2024-08-12T10:00:00.000Z') — that is what the UI emits.
  2. Validate in the client before submit; if you call the API directly, parse with dayjs/Date first and reject NaN.
  3. Confirm the year is within [1970, 9999] — values beyond 9999 are rejected to fit the SQL DATETIME range.
  4. If migrating historical data, clamp or skip rows with invalid dates instead of forwarding them.

Example fix

// before
if (obj.dateRange[0]) {
    const parsedDate = new Date(obj.dateRange[0]);
    if (isNaN(parsedDate.getTime()) || parsedDate.getFullYear() > 9999) {
        throw new Error("Invalid start date");
    }
    bean.start_date = obj.dateRange[0];
}

// after — normalise to ISO and report the bad value
if (obj.dateRange[0]) {
    const parsedDate = new Date(obj.dateRange[0]);
    if (isNaN(parsedDate.getTime()) || parsedDate.getFullYear() > 9999) {
        throw new Error(`Invalid start date: ${JSON.stringify(obj.dateRange[0])}`);
    }
    bean.start_date = parsedDate.toISOString();
}
Defensive patterns

Strategy: validation

Validate before calling

// Validate a dateRange start before POSTing to the maintenance API
function isValidMaintenanceDate(v) {
    if (!v) return true; // null/empty is allowed
    const d = new Date(v);
    return !isNaN(d.getTime()) && d.getFullYear() <= 9999;
}

Type guard

function isValidMaintenanceDate(v) {
    if (!v) return true;
    const d = new Date(v);
    return !isNaN(d.getTime()) && d.getFullYear() <= 9999;
}

Try / catch

try {
    await Maintenance.jsonToBean(bean, obj);
} catch (e) {
    if (/Invalid start date/.test(e.message)) {
        // surface a field-level error to the UI for dateRange[0]
    }
    throw e;
}

Prevention

When it happens

Trigger: A maintenance window payload whose dateRange[0] is a malformed string ('2024-13-45', 'asdf', ''), an impossible year (year 10000+), or a format Date cannot parse in this Node version. Commonly sent by a broken frontend date picker or a hand-crafted API request.

Common situations: Browser timezone/locale quirks that emit an unparseable string; copy-paste of a date with the wrong locale; automated scripts POSTing ISO strings with offset suffixes the parser rejects; bad migration data.

Related errors


AI-assisted analysis of louislam/uptime-kuma@6b5ea01557 (2026-08-12). Data as JSON: /api/errors/6e3d84ec2668cf7a. Report an issue: GitHub.