You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Appointments can be booked on dates where unavailability has been declared #146
I've searched existing issues and this isn't a duplicate.
This is a reproducible bug in Calnode — not a configuration/setup question or a feature request.
What's the bug?
Hi,
I encountered a bug earlier today where an appointment can be booked with a host who has declared unavailability for the day as long as at least one more host is available at that day.
If, however, all hosts are unavailable at that day, either due to overrides or simply not having added it to their availability, the day is greyed out and the client cannot book a meeting then.
What's particularly strange is that from my understanding, and I could be wrong at this, the timeslots presented as available belong to the host who is available (as it should be). But the appointment gets booked with the unavailable host.
"even--fewest upcoming bookings" or "priority" options in the hosts tab of the event type don't seem to make a difference, unless I explicitly give priority to the host I know will be available, in which case the unavailable one does not get booked at all, no matter how many appointments get booked (This is primarily where my above assumption that only the available host's timeslots are presented sources from).
To summarize in case something isn't clear enough: The unavailable host seems to be getting booked on the available one's timeslots. The host's date override isn't respected.
I will take a look see if I can spot the issue in the source code.
Steps to reproduce
Create an event type with two hosts (at least).
One of them adds an override.
Try to book a meeting on this event type.
The unavailable one gets assigned the meeting.
Try to book another one. Assuming both hosts work on the same hours, the same timeslot you just booked the meeting is not available, signaling that the timeslots presented belong to the available one (In the opposite case, the same timeslot would be available, as there are two hosts working at the same time). So the unavailable host is considered partially available by the app (?)
After a quick look in the code, I found that adding the following code snippet around line 800 of "internal\handler\booking_handler.go" (after validating the booking time and right before creating the booking) fixes the issue.
if et.RoutingMode == "round_robin" {
var availableCandidates []string
for _, hostID := range candidates {
ok, err := h.hostAvailableAt(r.Context(), hostID, et.ID, startAt.UTC(), endAt)
if err != nil {
h.logger.ErrorContext(r.Context(), "create booking: check host availability", "error", err)
h.writeError(w, http.StatusInternalServerError, "internal error")
return
}
if ok {
availableCandidates = append(availableCandidates, hostID)
}
}
candidates = availableCandidates
}
It checks the availability of every single host currently assigned to this event type on the event's start time. If a host is unavailable, the check fails and they are obviously not taken into consideration.
There might be some edge cases I have not yet considered, but this seems to do the trick for now.
If anyone has some input on this it is very welcome.
Fixed in #147, merged. Thanks again — your diagnosis and snippet were spot on.
One note on the fix, in case you want to follow it along: I moved the filter into a small helper and applied it to both creation entry points rather than just the REST handler. POST /v1/bookings is only one of them — createBookingForSlug is the shared path behind the MCP create_booking tool and the conversational booking assistant. Your snippet as written would have fixed the public booking page while leaving both of those still able to assign an unavailable host.
Also worth knowing for future reports: calendarFreeHosts can't catch this one. It filters on external calendar busy, and returns the pool untouched when no calendar provider is connected — which is the usual self-hosted case, and exactly why the override was ignored there.
Closing the issue; shout if you still see it on the next release.
Activity
pullfrog commentedon Oct 15, 2026
MinosChatzidakis commentedon Oct 15, 2026
After a quick look in the code, I found that adding the following code snippet around line 800 of "internal\handler\booking_handler.go" (after validating the booking time and right before creating the booking) fixes the issue.
if et.RoutingMode == "round_robin" {
var availableCandidates []string
for _, hostID := range candidates {
ok, err := h.hostAvailableAt(r.Context(), hostID, et.ID, startAt.UTC(), endAt)
if err != nil {
h.logger.ErrorContext(r.Context(), "create booking: check host availability", "error", err)
h.writeError(w, http.StatusInternalServerError, "internal error")
return
}
if ok {
availableCandidates = append(availableCandidates, hostID)
}
}
candidates = availableCandidates
}
It checks the availability of every single host currently assigned to this event type on the event's start time. If a host is unavailable, the check fails and they are obviously not taken into consideration.
There might be some edge cases I have not yet considered, but this seems to do the trick for now.
If anyone has some input on this it is very welcome.
fix(booking): never assign a round-robin host who is unavailable (#146)…
shockalotti commentedon Oct 15, 2026
Fixed in #147, merged. Thanks again — your diagnosis and snippet were spot on.
One note on the fix, in case you want to follow it along: I moved the filter into a small helper and applied it to both creation entry points rather than just the REST handler.
POST /v1/bookingsis only one of them —createBookingForSlugis the shared path behind the MCPcreate_bookingtool and the conversational booking assistant. Your snippet as written would have fixed the public booking page while leaving both of those still able to assign an unavailable host.Also worth knowing for future reports:
calendarFreeHostscan't catch this one. It filters on external calendar busy, and returns the pool untouched when no calendar provider is connected — which is the usual self-hosted case, and exactly why the override was ignored there.Closing the issue; shout if you still see it on the next release.