angular/components · error · Error

MomentDateAdapter: Cannot format invalid date.

Error message

MomentDateAdapter: Cannot format invalid date.

What it means

MomentDateAdapter.format clones the date and refuses to format an invalid Moment, because formatting an invalid date would silently emit 'Invalid Date' or empty output. It throws this error in ngDevMode so the developer learns the underlying date is invalid (bad parse, invalid components) at the formatting call site.

Source

Thrown at src/material-moment-adapter/adapter/moment-date-adapter.ts:187

    return result;
  }

  today(): Moment {
    return this._createMoment().locale(this.locale);
  }

  parse(value: unknown, parseFormat: string | string[]): Moment | null {
    if (value && typeof value == 'string') {
      return this._createMoment(value, parseFormat, this.locale);
    }
    return value ? this._createMoment(value).locale(this.locale) : null;
  }

  format(date: Moment, displayFormat: string): string {
    date = this.clone(date);
    if (!this.isValid(date) && (typeof ngDevMode === 'undefined' || ngDevMode)) {
      throw Error('MomentDateAdapter: Cannot format invalid date.');
    }
    return date.format(displayFormat);
  }

  addCalendarYears(date: Moment, years: number): Moment {
    return this.clone(date).add({years});
  }

  addCalendarMonths(date: Moment, months: number): Moment {
    return this.clone(date).add({months});
  }

  addCalendarDays(date: Moment, days: number): Moment {
    return this.clone(date).add({days});
  }

  toIso8601(date: Moment): string {
    return this.clone(date).format();

View on GitHub (pinned to 0411926e7d)

Solutions

  1. Check adapter.isValid(date) before calling format and handle the invalid branch (show placeholder/empty).
  2. Trace why the date is invalid — inspect date.creationData() / invalidReason() on the Moment.
  3. Use a parse fallback: if adapter.parse fails, fall back to today or null rather than formatting the invalid result.
  4. Verify you are not passing a raw string to format; deserialize first with adapter.deserialize/fromISOString.

Example fix

// before
const label = adapter.format(userDate, 'YYYY-MM-DD'); // userDate may be invalid
// after
const label = adapter.isValid(userDate) ? adapter.format(userDate, 'YYYY-MM-DD') : '';
Defensive patterns

Strategy: type-guard

Validate before calling

if (!adapter.isValid(date)) {
  return '';
}
const label = adapter.format(date, displayFormat);

Type guard

function isFormattable(adapter: MomentDateAdapter, date: Moment | null | undefined): date is Moment {
  return !!date && adapter.isValid(date);
}

Try / catch

try {
  return adapter.format(date, fmt);
} catch (e) {
  if (e instanceof Error && e.message.includes('Cannot format invalid date')) {
    console.warn('invalid moment', (date as any)?.invalidReason?.());
    return '';
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling format() with a Moment that failed to parse from a string, was built from invalid createDate input (production checks bypassed), or became invalid after invalid(null) / bad user input in a datepicker.

Common situations: Free-text date input parsed with strict mode failing, datepicker bound to garbage state, formatting a null-derived date, upstream regression where a createDate out-of-bounds check was skipped (prod builds).

Related errors


AI-assisted analysis of angular/components@0411926e7d (2026-08-31). Data as JSON: /api/errors/f002a739059a640d. Report an issue: GitHub.