calcom/cal.diy · warning · BadRequestException

Invalid datestring format. Expected format(ISO8061): 2025-04

Error message

Invalid datestring format. Expected format(ISO8061): 2025-04-12T13:17:56.324Z. Received: ${value}

What it means

Thrown by transformStringToDate when the provided time string is non-empty but does not contain the 'T' separator that separates the date portion from the time portion in ISO 8601 format. The function splits on 'T' and expects exactly two parts; any other result triggers HTTP 400. Note the error message itself contains typos ('ISO8061' should be 'ISO8601' and '2025-0412' is missing a hyphen).

Source

Thrown at apps/api/v2/src/platform/schedules/schedules_2024_04_15/inputs/create-availability.input.ts:30

  @IsDate()
  @Transform(({ value, key }: TransformFnParams) => transformStringToDate(value, key))
  startTime!: Date;

  @IsDate()
  @Transform(({ value, key }: TransformFnParams) => transformStringToDate(value, key))
  endTime!: Date;
}

function transformStringToDate(value: string, key: string): Date {
  if (!value) {
    throw new BadRequestException(
      `Missing ${key}. Expected value is in ISO8061 format e.g. 2025-0412T13:17:56.324Z`
    );
  }

  const dateTimeParts = value.split("T");
  if (dateTimeParts.length !== 2) {
    throw new BadRequestException(
      `Invalid datestring format. Expected format(ISO8061): 2025-04-12T13:17:56.324Z. Received: ${value}`
    );
  }

  const timePart = dateTimeParts[1].split(".")[0]; // Removes milliseconds
  const parts = timePart.split(":");

  if (parts.length !== 3) {
    throw new BadRequestException(
      `Invalid time format. Expected format(ISO8061): 2025-0412T13:17:56.324Z. Received: ${value}`
    );
  }
  const [hours, minutes, seconds] = parts.map(Number);

  if (hours < 0 || hours > 23) {
    throw new BadRequestException(`Invalid ${key} hours. Expected value between 0 and 23`);
  }

View on GitHub (pinned to 176037d0af)

Solutions

  1. Format startTime and endTime as full ISO 8601 strings with a 'T' separator: '2025-04-12T09:00:00.000Z'.
  2. Use JavaScript's toISOString() on a Date object to guarantee the correct format.
  3. If using date-fns, use format(date, "yyyy-MM-dd'T'HH:mm:ss.SSSxxx") or simply date.toISOString().

Example fix

// before
"startTime": "2025-04-12 09:00:00"
// after
"startTime": new Date('2025-04-12T09:00:00').toISOString()
Defensive patterns

Strategy: validation

Validate before calling

function toISO8601(date: Date): string {
  const iso = date.toISOString();
  // Verify it contains a 'T' separator
  if (!iso.includes('T')) {
    throw new Error(`Invalid ISO format: ${iso}`);
  }
  return iso;
}

// Ensure all time values pass through this before the API call
availability.startTime = toISO8601(new Date(2025, 3, 12, 9, 0, 0));

Type guard

function isValidISODateString(value: string): boolean {
  // Must contain 'T' separator and be parseable
  if (!value.includes('T')) return false;
  const d = new Date(value);
  return !isNaN(d.getTime());
}

Try / catch

try {
  await api.post('/v2/schedules', payload);
} catch (error) {
  if (error.response?.status === 400 && error.response.data.message?.includes('Invalid datestring format')) {
    // Reformat the time string to include 'T' separator and retry
    console.error('Date string missing T separator:', error.response.data.message);
  }
  throw error;
}

Prevention

When it happens

Trigger: Sending a date-only string like '2025-04-12' without a time component; sending a space-separated datetime like '2025-04-12 09:00:00' instead of 'T'; sending a Unix timestamp or other non-ISO format.

Common situations: Client uses date-fns format() without including time; frontend date picker returns only the date portion; locale-specific formatting uses a space instead of 'T'; sending a date string from a different API that uses a different separator.

Related errors


AI-assisted analysis of calcom/cal.diy@176037d0af (2026-08-12). Data as JSON: /api/errors/1bf0e1bd8afe12f6. Report an issue: GitHub.