Guide
Error Handling in Cal.com

Error Handling in Cal.com

[Alert component] is used to show errors:

In this guide, we analyze how errors are handled in a component in cal.com.

How to find out what error handling mechanisms are used in cal.com codebase? Pick a page on cal.com and find the page route in its source code

In this guide, we choose the bookings listing component.

[Insert screenshots of bookings page]

Bookings component depends purely on the query result to decide what to render based on query.status.

// picked from https://github.com/calcom/cal.com/blob/main/apps/web/modules/bookings/views/bookings-listing-view.tsx#L82C3-L95C5
const query = trpc.viewer.bookings.get.useInfiniteQuery(
    {
      limit: 10,
      filters: {
        ...filterQuery,
        status: filterQuery.status ?? status,
      },
    },
    {
      // first render has status `undefined`
      enabled: true,
      getNextPageParam: (lastPage) => lastPage.nextCursor,
    }
  );

In this guide, our focus is only on how errors are handled in a component. So, if there's an error encountered, query.status would be "error".

{
    query.status === "error" && 
    (
      <Alert severity="error" title={t("something_went_wrong")} message={query.error.message} />
    )
}

Alert is imported from packages/ui/components/alert/Alert.tsx

References:

  1. https://github.com/calcom/cal.com/blob/main/apps/web/pages/bookings/%5Bstatus%5D.tsx
  2. https://github.com/calcom/cal.com/blob/main/apps/web/modules/bookings/views/bookings-listing-view.tsx#L165
  3. https://github.com/calcom/cal.com/blob/main/packages/ui/components/alert/Alert.tsx // In auth/login error handling:
  4. https://github.com/calcom/cal.com/blob/main/apps/web/modules/auth/login-view.tsx#L232C1-L233C80

[Error tracking]: Cal.com uses Sentry to track production errors. The below code snippet is from cal.com/apps/web/intrumentation.ts

import * as Sentry from "@sentry/nextjs";

export function register() {
  if (process.env.NEXT_RUNTIME === "nodejs") {
    Sentry.init({
      dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
    });
  }

  if (process.env.NEXT_RUNTIME === "edge") {
    Sentry.init({
      dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
    });
  }
}

Read this official Sentry docs that explains how to setup Sentry in a Next.js project.

This intrumentation file above is automatically generated as part of Sentry setup. dsn: The DSN tells the SDK where to send the events. If this value is not provided, the SDK will try to read it from the SENTRY_DSN environment variable. If that variable also does not exist, the SDK will just not send any events.

In runtimes without a process environment (such as the browser) that fallback does not apply.

Learn more about DSN utilization.

References:

  1. https://github.com/calcom/cal.com/blob/main/apps/web/instrumentation.ts
  2. https://github.com/calcom/cal.com/blob/main/apps/web/sentry.client.config.ts
  3. https://docs.sentry.io/platforms/javascript/guides/nextjs/

[Error Boundary]

By default, if your application throws an error during rendering, React will remove its UI from the screen. To prevent this, you can wrap a part of your UI into an error boundary. An error boundary is a special component that lets you display some fallback UI instead of the part that crashed—for example, an error message.

React docs explains how to write your own boundary

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    // Update state so the next render will show the fallback UI.
    return { hasError: true };
  }

  componentDidCatch(error, info) {
    // Example "componentStack":
    //   in ComponentThatThrows (created by App)
    //   in ErrorBoundary (created by App)
    //   in div (created by App)
    //   in App
    logErrorToMyService(error, info.componentStack);
  }

  render() {
    if (this.state.hasError) {
      // You can render any custom fallback UI
      return this.props.fallback;
    }

    return this.props.children;
  }
}

You can write your own ErrorBoundary or use react-error-boundary, recommended by React.

Guess the kind of ErrorBoundary used in cal.com?

import type { ErrorInfo } from "react";
import React from "react";

class ErrorBoundary extends React.Component<
  { children: React.ReactNode; message?: string },
  { error: Error | null; errorInfo: ErrorInfo | null }
> {
  constructor(props: { children: React.ReactNode } | Readonly<{ children: React.ReactNode }>) {
    super(props);
    this.state = { error: null, errorInfo: null };
  }

  componentDidCatch?(error: Error, errorInfo: ErrorInfo) {
    // Catch errors in any components below and re-render with error message
    this.setState({ error, errorInfo });
    // You can also log error messages to an error reporting service here
  }

  render() {
    // do not intercept next-not-found error, allow displaying not-found.tsx page when notFound() is thrown on server side
    if (
      this.state.error !== null &&
      "digest" in this.state.error &&
      this.state.error.digest === "NEXT_NOT_FOUND"
    ) {
      return this.props.children;
    }

    if (this.state.errorInfo) {
      // Error path
      return (
        <div>
          <h2>{this.props.message || "Something went wrong."}</h2>
          <details style={{ whiteSpace: "pre-wrap" }}>
            {this.state.error && this.state.error.toString()}
          </details>
        </div>
      );
    }
    // Normally, just render children
    return this.props.children;
  }
}

export default ErrorBoundary;

cal.com has its own ErrorBoundary class. It has componentDidCatch and render methods defined. Although, documentation provides the example containing getDerivedStateFromError, it looks like this getDerivedStateFromError method is not used in cal.com ErrorBoundary class.

References:

  1. https://github.com/search?q=repo%3Acalcom%2Fcal.com%20ErrorBoundary&type=code
  2. https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary
  3. https://github.com/bvaughn/react-error-boundary
  4. https://github.com/calcom/cal.com/blob/5bbccad41d625250ac03a6683e751b8ed6650721/packages/ui/components/errorBoundary/ErrorBoundary.tsx#L4