Skip to content

fix: daily ux + calendar + user.fm#849

Open
deardarlingoose wants to merge 12 commits intomainfrom
fix-daily-ux
Open

fix: daily ux + calendar + user.fm#849
deardarlingoose wants to merge 12 commits intomainfrom
fix-daily-ux

Conversation

@deardarlingoose
Copy link
Contributor

@deardarlingoose deardarlingoose commented Feb 6, 2026

User description

user report: user.fm would pull duplicate events from Cal.com and google calendar - normal workflow causes duped meetings

also, people kicked from expired meetings with unhelpful error

LLM DESCRIPTION PROOFRED:

Summary

  • Better error messages when users get disconnected from Daily.co meetings — instead of generic "Failed to join meeting", shows specific reasons (connection lost, meeting ended, ejected) with actionable buttons
  • Prevent duplicate meetings from aggregated ICS calendar feeds — when the same event appears with different UIDs (Cal.com + Google Calendar), only one meeting is created

Context

Feb 2 incident: user kicked from Max's room, saw "Failed to join meeting" with no way to recover. Investigation found two issues: (1) no error context shown to users on disconnect, (2) duplicate meetings created from aggregated calendar feed containing both Cal.com
and Google Calendar copies of each event.

Changes

Daily.co error UX (DailyRoom.tsx)

  • Listen to Daily.co error event (previously only left-meeting was handled)
  • Show specific error messages per DailyFatalErrorType: connection-error, exp-room, ejected, with appropriate recovery actions
  • Join failure now surfaces actual API error detail ("Meeting has ended" etc.) instead of generic message
  • "Back to Room" and "Try Rejoining" buttons on error screens

ICS meeting dedup (meetings.py, ics_sync.py)

  • Before creating a meeting for a calendar event, check if a meeting already exists for the same room with identical (start_date, end_date)
  • Prevents duplicate meetings when aggregated feeds contain the same event with different ics_uid values
  • Duplicate calendar_event rows are left intact (they are technically different records)

Test plan

  • ICS dedup: 2 new tests pass (test_ics_dedup.py)
  • ICS dedup: existing ICS + meeting tests pass (no regressions)
  • Lint/format passes
  • Manual: verify Daily.co error screens render correctly in a live meeting
  • Manual: verify duplicate meetings no longer appear in Max's MeetingSelection

PR Type

Bug fix, Enhancement


Description

  • Fix duplicate meetings from aggregated calendar feeds

  • Improve Daily.co error handling with specific messages

  • Add time-window deduplication for calendar events

  • Create user-friendly error screens with recovery options


Changes walkthrough 📝

Relevant files
Enhancement
meetings.py
Add method to detect duplicate meetings by time window     

server/reflector/db/meetings.py

  • Added new method get_by_room_and_time_window to check if a meeting
    already exists for a room with the same time window
  • Method takes room, start_date, and end_date parameters to find
    potential duplicates
  • Returns Meeting object or None if no duplicate exists
  • +21/-0   
    DailyRoom.tsx
    Enhance Daily.co error handling and UI                                     

    www/app/[roomName]/components/DailyRoom.tsx

  • Added error handling for Daily.co fatal errors with specific user
    messages
  • Created FatalErrorScreen component to display appropriate error
    messages
  • Added error event listener to Daily.co frame
  • Implemented different UI actions based on error type (rejoinable vs
    non-rejoinable)
  • Improved join failure error display to show actual API error details
  • +94/-3   
    Bug fix
    ics_sync.py
    Implement calendar event deduplication logic                         

    server/reflector/worker/ics_sync.py

  • Modified create_upcoming_meetings_for_event to check for existing
    meetings with same time window
  • Added deduplication logic to prevent duplicate meetings from
    aggregated calendar feeds
  • Improved type hints and removed fallback to default duration
  • Added logging for skipped duplicate events
  • +19/-7   
    Tests
    test_ics_dedup.py
    Add tests for calendar event deduplication                             

    server/tests/test_ics_dedup.py

  • Added new test file with two test cases for calendar event
    deduplication
  • First test verifies same event with different UIDs creates only one
    meeting
  • Second test confirms different time windows still create separate
    meetings
  • Tests use mocks to simulate platform client behavior
  • +190/-0 
    Documentation
    apiHooks.ts
    Add reference marker for ApiError type issue                         

    www/app/lib/apiHooks.ts

  • Added reference marker for ApiError type casting issue
  • No functional changes, just documentation for future reference
  • +1/-0     

    Need help?
  • Type /help how to ... in the comments thread for any questions about PR-Agent usage.
  • Check out the documentation for more information.
  • Handle fatal errors from Daily.co SDK (connection-error, exp-room,
    ejected, etc.) with user-friendly messages and appropriate actions.
    Improve join failure display to show actual API error detail.
    When Cal.com events appear in an aggregated ICS feed, the same event
    gets two different UIDs (one from Cal.com, one from Google Calendar).
    This caused duplicate meetings to be created for the same time slot.
    
    Add time-window dedup check in create_upcoming_meetings_for_event:
    after verifying no meeting exists for the calendar_event_id, also check
    if a meeting already exists for the same room + start_date + end_date.
    @deardarlingoose deardarlingoose changed the title fix: daily ux fix: daily ux + calendar + user.fm Feb 6, 2026
    @deardarlingoose deardarlingoose marked this pull request as ready for review February 6, 2026 16:34
    @pr-agent-monadical
    Copy link
    Contributor

    PR Reviewer Guide 🔍

    Here are some key observations to aid the review process:

    ⏱️ Estimated effort to review: 3 🔵🔵🔵⚪⚪
    🧪 PR contains tests
    🔒 No security concerns identified
    ⚡ Recommended focus areas for review

    Error Handling

    The error handling implementation shows specific error messages but doesn't log errors for monitoring/debugging. Consider adding error logging to track frequency and types of errors users encounter.

    const handleError = useCallback((ev: DailyEventObjectFatalError) => {
      const error: FatalError = {
        type: ev.error?.type ?? "unknown",
        message: ev.errorMsg,
      };
      setFatalError(error);
    }, []);
    Potential Race Condition

    The deduplication logic checks for existing meetings by time window, but there's no transaction or lock mechanism. If two calendar events with the same time window are processed concurrently, duplicate meetings could still be created.

    # Prevent duplicate meetings from aggregated calendar feeds
    # (e.g. same event appears with different UIDs from Cal.com and Google Calendar)
    end_date = event.end_time
    existing_by_time = await meetings_controller.get_by_room_and_time_window(
        room, event.start_time, end_date
    )
    if existing_by_time:
        logger.info(
            "Skipping duplicate calendar event - meeting already exists for this time window",
            room_id=room.id,
            event_id=event.id,
            existing_meeting_id=existing_by_time.id,
        )
        return

    Comment on lines +308 to +314
    const handleError = useCallback((ev: DailyEventObjectFatalError) => {
    const error: FatalError = {
    type: ev.error?.type ?? "unknown",
    message: ev.errorMsg,
    };
    setFatalError(error);
    }, []);
    Copy link
    Contributor

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    Suggestion: The error handler should log the error to the console for debugging purposes, especially since it's handling fatal errors that could impact user experience. [general, importance: 5]

    Suggested change
    const handleError = useCallback((ev: DailyEventObjectFatalError) => {
    const error: FatalError = {
    type: ev.error?.type ?? "unknown",
    message: ev.errorMsg,
    };
    setFatalError(error);
    }, []);
    const handleError = useCallback((ev: DailyEventObjectFatalError) => {
    console.error("Daily fatal error:", ev.errorMsg, ev.error);
    const error: FatalError = {
    type: ev.error?.type ?? "unknown",
    message: ev.errorMsg,
    };
    setFatalError(error);
    }, []);

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

    Projects

    None yet

    Development

    Successfully merging this pull request may close these issues.

    3 participants