Skip to content

Booking page crashes with "RangeError: Invalid time value" on invalid ?month= or ?date= query params #30302

Open

Description

@WojciechCzechowski

Issue Summary

The Booker reads ?month= and ?date= from the URL without validating them. A malformed value makes the whole booking page crash with the generic "It's not you, it's us" error page. Other odd values are accepted silently and lead to confusing states: months in the past, months that roll over (2026-13 shows January 2027), and absurd years (99999-01 shows September 9999).

These params appear in shareable/booking links and are easy to get wrong (hand-edited links, truncated URLs, broken integrations that build links), so a bad link currently dead-ends the booker instead of falling back to a sensible default.

Steps to Reproduce

  1. Open any public booking page with an invalid param, e.g. http://localhost:3000/pro/30min?layout=month_view&month=garbage.
  2. Or .../pro/30min?layout=month_view&date=garbage.

Results observed on a local dev instance (seeded pro user, event 30min, today = 2026-10-06):

Query params Result
month=garbage Page replaced by error screen: RangeError: Invalid time value
date=garbage Same crash (even with a valid month=2026-10)
month=2026-13 Header shows "January 2027"; URL keeps month=2026-13 (dayjs overflow, not normalized)
month=2026-1 Header shows "January 2026", a past month, with a "No availability" dialog
month=2020-01 "January 2020" with a "No availability" dialog (unreachable through the UI)
date=2026-02-31 Rolls over to "March 2026", a past month
month=99999-01 Renders "September 9999"
month=2076-10 Renders October 2076 with bookable days (the event has an unlimited period, so this may be intended)
month= (empty) Falls back to the current month (fine)

Actual Results

  • Invalid values crash the page. Console: RangeError: Invalid time value at Date.toISOString in useTimesForSchedule (packages/features/schedules/hooks/useTimesForSchedule.ts, the monthDayjs.startOf("month").toISOString() calls around lines 117-124).
  • Past, overflowing and extreme values are accepted as-is into the Booker store; the URL is not rewritten.

Expected Results

  • An invalid or unparseable month/date never crashes the page; the Booker falls back to the current month (and rewrites the URL to match).
  • Past months/dates fall back to the current month, since they can't be reached through the UI.
  • Values like 2026-13 or 2026-02-31 are treated as invalid, not silently rolled over.

Technical details

  • The values enter through the Booker store initial state: packages/features/bookings/Booker/store.ts (month: initializer reading getQueryParam("month"), around lines 520-525, and selectedDate: getQueryParam("date"), around line 457). Neither is validated.
  • Suggested fix: validate with strict dayjs parsing (YYYY-MM / YYYY-MM-DD with strict = true) and clamp to >= current month in one small helper used by both initializers, with unit tests (Vitest, TZ=UTC). No UI or translation changes needed.
  • Open question for maintainers: for event types with an unlimited booking period, should there be an upper bound on how far ahead ?month= may point (e.g. 12 or 24 months)? Every month triggers a full slots computation, so an arbitrary far-future month is a cheap way to make the server do work. I'd rather ask than assume, and I would not add a bound in the first PR unless asked.
  • I considered a "polite modal" for out-of-range dates, but a silent fallback needs no new UI or strings and keeps the change small. Happy to do the modal instead if maintainers prefer.
  • I searched existing issues and PRs and found nothing about validating these params. Closest: merged fix: booker atom not resetting month query param #14715, fix: Ensure previous slots do appear if the month search param is removed  #18097, feat: prevent automatic query parameters when opening booking page #18132, and closed fix: Ensure correct fallback to current month when 'month' query param is … #18096, which touched month param handling but not validation.
  • I'm happy to open a PR for this.
  • Environment: Cal.diy main at 54343aa, local dev server (Next 16), Chrome, macOS. Not verified on a production build.

Evidence

Image Image

Activity

  1. WojciechCzechowski commented on Oct 7, 2026

    @WojciechCzechowski
    Author

    Hi @nishantsingh02, thanks for picking this up. I saw your fork PR (nishantsingh02#1) and the validation helper looks like a good approach.

    One thing to flag: that PR was merged into your fork's main, so the change isn't in calcom/cal.diy yet. For it to land here, a PR needs to be opened from your branch against calcom/cal.diy main.

    A small note on the change itself: it sanitizes the store's initial month/date values, but as far as I can tell the invalid value stays in the address bar (e.g. ?month=garbage isn't rewritten to the current month). That doesn't crash anymore, but the URL and the displayed month can disagree, and a shared link keeps the bad value. It may be worth rewriting the param to the sanitized value, or deciding explicitly that leaving it is fine.

    Are you planning to open the upstream PR? If so, go ahead. If you'd rather not, I can open it myself, with tests. Let me know either way so we don't duplicate work. If I haven't heard back in a couple of days, I'll go ahead and open one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    🐛 bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions