Skip to content

Appointments can be booked on dates where unavailability has been declared #146

Closed

Description

@MinosChatzidakis

Before submitting

  • 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

  1. Create an event type with two hosts (at least).
  2. One of them adds an override.
  3. Try to book a meeting on this event type.
  4. The unavailable one gets assigned the meeting.

  1. 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 (?)

Calnode version / commit

v.0.10.1

How are you running Calnode?

Self-hosted — Docker

Logs, screenshots, or anything else

No response

Activity

  1. pullfrog commented on Oct 15, 2026

    @pullfrog
    Contributor
  2. MinosChatzidakis commented on Oct 15, 2026

    @MinosChatzidakis
    Author

    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.

  3. shockalotti commented on Oct 15, 2026

    @shockalotti
    Contributor

    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.

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