Compare commits

...
Author SHA1 Message Date
Sonarly Claude Code e310c42bbf Missing date validation in FormDateFieldInput crashes workflow editor
https://sonarly.com/issue/4345?type=bug

The `useParsePlainDateToDateInputString` hook calls `format()` from date-fns without validating that `parse()` returned a valid date, causing a `RangeError: Invalid time value` when a workflow step's date field contains a value not in `yyyy-MM-dd` format.

Fix: Added `isValid()` checks from date-fns to the two Date formatting hooks that were missing them, matching the existing pattern in the DateTime equivalent hook (`useParseJSDateToIMaskDateTimeInputString`):

**1. `useParsePlainDateToDateInputString.ts`** — Added `isValid(parsedDate)` check after `parse()` and before `format()`. When the input plain date string doesn't match `yyyy-MM-dd` format, `parse()` returns an Invalid Date. The new guard returns `''` instead of letting `format()` throw `RangeError: Invalid time value`. This is the primary fix for the Sentry error, as this function is called in `FormDateFieldInput`'s `useState` initializer.

**2. `useParseJSDateToIMaskDateInputString.ts`** — Added `isDefined(jsDate) || !isValid(jsDate)` check before `format()`, exactly mirroring the guard in `useParseJSDateToIMaskDateTimeInputString`. This is a defensive fix for the same class of bug in the IMask formatting callback used by `DatePickerInput`.

Both changes return `''` (empty string) for invalid dates, which is the same behavior the DateTime hooks use. The calling components already handle empty strings gracefully — `FormDateFieldInput` shows a placeholder, and IMask treats empty as a cleared value.
2026-03-06 13:21:46 +00:00
2 changed files with 11 additions and 2 deletions
@@ -1,12 +1,17 @@
import { useDateTimeFormat } from '@/localization/hooks/useDateTimeFormat';
import { format } from 'date-fns';
import { format, isValid } from 'date-fns';
import { isDefined } from 'twenty-shared/utils';
import { getDateFormatStringForDatePickerInputMask } from '~/utils/date-utils';
export const useParseJSDateToIMaskDateInputString = () => {
const { dateFormat } = useDateTimeFormat();
const parseIMaskJSDateIMaskDateInputString = (jsDate: Date) => {
if (!isDefined(jsDate) || !isValid(jsDate)) {
return '';
}
const parsingFormat = getDateFormatStringForDatePickerInputMask(dateFormat);
const formattedDate = format(jsDate, parsingFormat);
@@ -1,6 +1,6 @@
import { useDateTimeFormat } from '@/localization/hooks/useDateTimeFormat';
import { format, parse } from 'date-fns';
import { format, isValid, parse } from 'date-fns';
import { DATE_TYPE_FORMAT } from 'twenty-shared/constants';
import { getDateFormatStringForDatePickerInputMask } from '~/utils/date-utils';
@@ -12,6 +12,10 @@ export const useParsePlainDateToDateInputString = () => {
const parsedDate = parse(plainDate, DATE_TYPE_FORMAT, new Date());
if (!isValid(parsedDate)) {
return '';
}
const formattedDate = format(parsedDate, parsingFormat);
return formattedDate;