Skip to content

Comments

fix: booker-atom-401-error-rescheduleUid#23495

Closed
hemantmm wants to merge 11 commits intocalcom:mainfrom
hemantmm:booker-atom-401-error
Closed

fix: booker-atom-401-error-rescheduleUid#23495
hemantmm wants to merge 11 commits intocalcom:mainfrom
hemantmm:booker-atom-401-error

Conversation

@hemantmm
Copy link
Contributor

@hemantmm hemantmm commented Sep 1, 2025

closes: #20949

What does this PR do?

These changes ensure that the rescheduleUiD is only considered valid if they are non-empty and not the string "null". It prevents passing invalid or empty UIDs to the backend API, which would otherwise result in 401 Unauthorized errors.

The update applies this check throughout the Booker Atom's hooks, components, and store initialization, and adds a documentation note to warn developers not to pass "null" or empty strings for these props. This results in more robust handling of booking rescheduling and avoids unnecessary or invalid API calls.

Video:

Before:

Screen.Recording.2025-09-04.at.18.52.13.mov

After:

Screen.Recording.2025-09-04.at.18.50.22.mov

Mandatory Tasks (DO NOT REMOVE)

  • I have self-reviewed the code (A decent size PR without self-review might be rejected).
  • I have updated the developer docs in /docs if this PR makes changes that would require a documentation change. If N/A, write N/A here and check the checkbox.
  • I confirm automated tests are in place that prove my fix is effective or that my feature works.

How should this be tested?

  • Are there environment variables that should be set?
  • What are the minimal test data to have?
  • What is expected (happy path) to have (input and output)?
  • Any other important info that could help to test that PR

Checklist

  • I haven't read the contributing guide
  • My code doesn't follow the style guidelines of this project
  • I haven't commented my code, particularly in hard-to-understand areas
  • I haven't checked if my changes generate no new warnings

@hemantmm hemantmm requested a review from a team September 1, 2025 13:12
@hemantmm hemantmm requested a review from a team as a code owner September 1, 2025 13:12
@vercel
Copy link

vercel bot commented Sep 1, 2025

@hemantmm is attempting to deploy a commit to the cal Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 1, 2025

Walkthrough

This PR standardizes handling of rescheduleUid and bookingUid across the Booker feature: it sanitizes these values in the store and initialization paths, normalizes them when read from URL and wrapper props, tightens checks in hooks and query enablement to reject the literal strings "null" and "", and updates downstream logic (isRescheduling, view selection, success event routing, and redirect params). A documentation note was added advising not to pass "null" or empty strings for these props. No public API signatures were changed.

Assessment against linked issues

Objective Addressed Explanation
Prevent 401 on bookings when rescheduleUid is present by only triggering reschedule logic/fetch with a valid UID (#20949, CAL-5659)
Normalize/sanitize rescheduleUid and bookingUid from URL, props, and store to avoid passing "null" or "" through the flow (#20949, CAL-5659)
Ensure view/schema selection and success event routing treat reschedule only when UID is valid (#20949, CAL-5659)

Possibly related PRs


📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between e8c32ba and 9ea5313.

📒 Files selected for processing (1)
  • packages/features/bookings/Booker/store.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/features/bookings/Booker/store.ts
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions github-actions bot added api area: API, enterprise API, access token, OAuth Low priority Created by Linear-GitHub Sync labels Sep 1, 2025
@graphite-app graphite-app bot added the community Created by Linear-GitHub Sync label Sep 1, 2025
@github-actions github-actions bot added Stale 🐛 bug Something isn't working labels Sep 1, 2025
@graphite-app graphite-app bot requested a review from a team September 1, 2025 13:12
@dosubot dosubot bot added the platform Anything related to our platform plan label Sep 1, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (5)
packages/platform/atoms/hooks/bookings/useGetBookingForReschedule.ts (1)

46-49: Don’t swallow errors in queryFn catch; rethrow to set isError

Without rethrow, React Query treats failures as success with undefined.

-        .catch((err) => {
-          props.onError?.(err);
-        });
+        .catch((err) => {
+          props.onError?.(err);
+          throw err;
+        });
packages/platform/atoms/booker/BookerPlatformWrapper.tsx (1)

298-306: Sanitize all rescheduleUid props in BookerPlatformWrapper
Wrap props.rescheduleUid to exclude "", "null", or null before passing to hooks/APIs to prevent invalid values.

Apply this pattern at:

  • line 181 (rescheduleUid: props.rescheduleUid ?? null)
  • line 197 (rescheduleUid: props.rescheduleUid ?? null)
  • line 305 (rescheduleUid: props.rescheduleUid)
-    rescheduleUid: props.rescheduleUid,
+    rescheduleUid:
+      props.rescheduleUid && props.rescheduleUid !== "null" && props.rescheduleUid !== ""
+        ? props.rescheduleUid
+        : undefined,
packages/features/bookings/Booker/store.ts (2)

376-386: Bug: reschedule check uses unsanitized input; use the sanitized store value.

The condition still reads the raw rescheduleUid arg. If a caller passes the literal "null", this block will incorrectly execute. Use the post-set, sanitized value from the store.

-      if (rescheduleUid && bookingData) {
+      if (get().rescheduleUid && bookingData) {
         set({ selectedTimeslot: null });
         const originalBookingLength = dayjs(bookingData?.endTime).diff(
           dayjs(bookingData?.startTime),
           "minutes"
         );
         set({ selectedDuration: originalBookingLength });
         if (!isPlatform || allowUpdatingUrlParams) {
           updateQueryParam("duration", originalBookingLength ?? "");
         }
       }

282-286: Remove “null” literals from URL params; omit the param when absent

  • packages/features/bookings/Booker/store.ts: replace
    updateQueryParam("bookingUid", seatedEventData.bookingUid ?? "null")
    with a conditional that calls removeQueryParam("bookingUid") when bookingUid is missing.
  • apps/web/lib/reschedule/[uid]/getServerSideProps.ts: eliminate the eventType.seatsPerTimeSlot ? "&bookingUid=null" : "" branch and only append &bookingUid=<id> if a real bookingUid exists.
packages/features/bookings/Booker/components/hooks/useBookings.ts (1)

347-357: Sanitize UID coming from server errors before writing to the store.

This path bypasses initialization and can reintroduce the literal "null" or empty strings into state.

-      if (error.message === ErrorCode.BookerLimitExceededReschedule && error.data?.rescheduleUid) {
-        useBookerStore.setState({
-          rescheduleUid: error.data?.rescheduleUid,
-        });
+      if (error.message === ErrorCode.BookerLimitExceededReschedule) {
+        const nextUid =
+          error.data?.rescheduleUid &&
+          error.data.rescheduleUid !== "null" &&
+          error.data.rescheduleUid !== ""
+            ? error.data.rescheduleUid
+            : null;
+        useBookerStore.setState({ rescheduleUid: nextUid });
       }
🧹 Nitpick comments (7)
packages/platform/atoms/hooks/bookings/useGetBookingForReschedule.ts (1)

50-51: Consolidate UID validation and reuse sanitized value for key/path/enabled

Avoid duplicating checks and ensure cache keys exclude invalid UIDs.

Apply this minimal change here:

-    enabled: isInit && !!props?.uid && props.uid !== "null" && props.uid !== "",
+    enabled: isInit && Boolean(validUid),

Outside this hunk, define and reuse a sanitized UID:

// right after isInit
const validUid = props.uid && props.uid !== "null" && props.uid.trim() !== "" ? props.uid : undefined;
const pathname = validUid ? `/${V2_ENDPOINTS.bookings}/${validUid}/reschedule` : "";

And update:

  • queryKey: [QUERY_KEY, validUid]
  • Only call http.get when validUid is defined.
packages/platform/atoms/booker/BookerPlatformWrapper.tsx (2)

135-141: Compute once, reuse sanitized UID for reschedule fetch

Precompute a single uidForReschedule and pass it here; this also enables reuse in cleanup.

-  useGetBookingForReschedule({
-    uid:
-      props.rescheduleUid && props.rescheduleUid !== "null" && props.rescheduleUid !== ""
-        ? props.rescheduleUid
-        : props.bookingUid && props.bookingUid !== "null" && props.bookingUid !== ""
-        ? props.bookingUid
-        : "",
+  // above this call (outside this hunk), add:
+  // const uidForReschedule =
+  //   props.rescheduleUid && props.rescheduleUid !== "null" && props.rescheduleUid !== ""
+  //     ? props.rescheduleUid
+  //     : props.bookingUid && props.bookingUid !== "null" && props.bookingUid !== ""
+  //     ? props.bookingUid
+  //     : "";
+  useGetBookingForReschedule({
+    uid: uidForReschedule,
     onSuccess: (data) => {
       setBookingData(data);
     },
   });

491-497: Cleanup should remove the actual query key used (handles fallback to bookingUid)

Currently only removes by props.rescheduleUid, leaving possible stale cache when falling back to bookingUid.

-        queryClient.removeQueries({
-          queryKey: [BOOKING_RESCHEDULE_KEY, props.rescheduleUid],
-          exact: true,
-        });
+        queryClient.removeQueries({
+          queryKey: [BOOKING_RESCHEDULE_KEY, uidForReschedule],
+          exact: true,
+        });
packages/features/bookings/Booker/components/hooks/useBookingForm.ts (1)

50-52: De-duplicate UID validation via a shared helper

Multiple files replicate the same checks; prefer isValidUid(uid).

-            view:
-              rescheduleUid && rescheduleUid !== "null" && rescheduleUid !== "" ? "reschedule" : "booking",
+            view: isValidUid(rescheduleUid) ? "reschedule" : "booking",

Outside this hunk, add once per module (or import from a shared util):

const isValidUid = (uid?: string | null) => typeof uid === "string" && uid !== "null" && uid.trim() !== "";
packages/platform/atoms/booker/BookerWebWrapper.tsx (2)

62-68: Use useSearchParams (already available) and trim; avoid reparsing window.location.search

Simplifies SSR checks and keeps logic consistent.

-  const rescheduleUid =
-    typeof window !== "undefined"
-      ? (() => {
-          const val = new URLSearchParams(window.location.search).get("rescheduleUid");
-          return val && val !== "null" && val !== "" ? val : null;
-        })()
-      : null;
+  const rescheduleUid = useMemo(() => {
+    const val = searchParams?.get("rescheduleUid");
+    return val && val !== "null" && val.trim() !== "" ? val : null;
+  }, [searchParams]);

71-77: Same simplification for bookingUid; prefer useSearchParams + trim

Keeps behavior consistent and reduces duplication.

-  const bookingUid =
-    typeof window !== "undefined"
-      ? (() => {
-          const val = new URLSearchParams(window.location.search).get("bookingUid");
-          return val && val !== "null" && val !== "" ? val : null;
-        })()
-      : null;
+  const bookingUid = useMemo(() => {
+    const val = searchParams?.get("bookingUid");
+    return val && val !== "null" && val.trim() !== "" ? val : null;
+  }, [searchParams]);
packages/features/bookings/Booker/components/hooks/useBookings.ts (1)

156-156: Simplify and rely on store-level sanitization.

rescheduleUid !== "null" is redundant after store sanitization.

-  const isRescheduling = !!rescheduleUid && rescheduleUid !== "null" && !!bookingData;
+  const isRescheduling = Boolean(rescheduleUid && bookingData);
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 712467a and 64ccdc4.

📒 Files selected for processing (7)
  • docs/platform/atoms/booker.mdx (1 hunks)
  • packages/features/bookings/Booker/components/hooks/useBookingForm.ts (1 hunks)
  • packages/features/bookings/Booker/components/hooks/useBookings.ts (1 hunks)
  • packages/features/bookings/Booker/store.ts (1 hunks)
  • packages/platform/atoms/booker/BookerPlatformWrapper.tsx (1 hunks)
  • packages/platform/atoms/booker/BookerWebWrapper.tsx (1 hunks)
  • packages/platform/atoms/hooks/bookings/useGetBookingForReschedule.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

Always use t() for text localization in frontend code; direct text embedding should trigger a warning

Files:

  • packages/platform/atoms/booker/BookerPlatformWrapper.tsx
  • packages/platform/atoms/booker/BookerWebWrapper.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js .utc() in hot paths like loops

Files:

  • packages/platform/atoms/booker/BookerPlatformWrapper.tsx
  • packages/features/bookings/Booker/store.ts
  • packages/features/bookings/Booker/components/hooks/useBookingForm.ts
  • packages/platform/atoms/hooks/bookings/useGetBookingForReschedule.ts
  • packages/platform/atoms/booker/BookerWebWrapper.tsx
  • packages/features/bookings/Booker/components/hooks/useBookings.ts
**/*.{ts,tsx,js,jsx}

⚙️ CodeRabbit configuration file

Flag default exports and encourage named exports. Named exports provide better tree-shaking, easier refactoring, and clearer imports. Exempt main components like pages, layouts, and components that serve as the primary export of a module.

Files:

  • packages/platform/atoms/booker/BookerPlatformWrapper.tsx
  • packages/features/bookings/Booker/store.ts
  • packages/features/bookings/Booker/components/hooks/useBookingForm.ts
  • packages/platform/atoms/hooks/bookings/useGetBookingForReschedule.ts
  • packages/platform/atoms/booker/BookerWebWrapper.tsx
  • packages/features/bookings/Booker/components/hooks/useBookings.ts
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

**/*.ts: For Prisma queries, only select data you need; never use include, always use select
Ensure the credential.key field is never returned from tRPC endpoints or APIs

Files:

  • packages/features/bookings/Booker/store.ts
  • packages/features/bookings/Booker/components/hooks/useBookingForm.ts
  • packages/platform/atoms/hooks/bookings/useGetBookingForReschedule.ts
  • packages/features/bookings/Booker/components/hooks/useBookings.ts
🧠 Learnings (3)
📚 Learning: 2025-08-27T13:32:46.887Z
Learnt from: supalarry
PR: calcom/cal.com#23364
File: apps/api/v2/src/ee/event-types/event-types_2024_06_14/transformers/internal-to-api/internal-to-api.spec.ts:295-296
Timestamp: 2025-08-27T13:32:46.887Z
Learning: In calcom/cal.com, when transforming booking fields from internal to API format, tests in organizations-event-types.e2e-spec.ts already expect name field label and placeholder to be empty strings ("") rather than undefined. PR changes that set these to explicit empty strings are typically fixing implementation to match existing test expectations rather than breaking changes.

Applied to files:

  • packages/features/bookings/Booker/store.ts
📚 Learning: 2025-07-15T12:59:34.389Z
Learnt from: eunjae-lee
PR: calcom/cal.com#22106
File: packages/features/insights/components/FailedBookingsByField.tsx:65-71
Timestamp: 2025-07-15T12:59:34.389Z
Learning: In the FailedBookingsByField component (packages/features/insights/components/FailedBookingsByField.tsx), although routingFormId is typed as optional in useInsightsParameters, the system automatically enforces a routing form filter, so routingFormId is always present in practice. This means the data always contains only one entry, making the single-entry destructuring approach safe.

Applied to files:

  • packages/features/bookings/Booker/components/hooks/useBookingForm.ts
📚 Learning: 2025-08-19T09:47:49.478Z
Learnt from: eunjae-lee
PR: calcom/cal.com#23166
File: packages/prisma/migrations/20250818151914_routing_form_response_denormalized_backfill2/migration.sql:65-66
Timestamp: 2025-08-19T09:47:49.478Z
Learning: The Booking table has a unique constraint and index on the uid column (defined as `uid String unique` in schema.prisma), so JOINs on Booking.uid have optimal performance and don't require additional indexing.

Applied to files:

  • packages/platform/atoms/hooks/bookings/useGetBookingForReschedule.ts
🪛 LanguageTool
docs/platform/atoms/booker.mdx

[grammar] ~134-~134: There might be a mistake here.
Context: ... | > Note: > When using rescheduleUid or `bookingUi...

(QB_NEW_EN)


[grammar] ~135-~135: There might be a mistake here.
Context: ...e prop or pass null. Passing "null" or empty string may result in a 401 Unauth...

(QB_NEW_EN)

⏰ Context from checks skipped due to timeout of 180000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Install dependencies / Yarn install & cache
🔇 Additional comments (3)
packages/features/bookings/Booker/components/hooks/useBookingForm.ts (1)

50-52: LGTM — stricter check avoids accidental “reschedule” mode

The additional guards on "null"/"" are correct and align with the PR’s objective.

packages/features/bookings/Booker/store.ts (1)

341-345: Sanitization of rescheduleUid/bookingUid looks good.

Guarding against "null" and "" aligns with the PR goal and prevents accidental auth errors.

packages/features/bookings/Booker/components/hooks/useBookings.ts (1)

324-331: Former time inclusion only when rescheduling — LGTM.

Conditionally setting formerTime based on isRescheduling matches the new contract.

Also applies to: 429-431

Signed-off-by: Hemant M Mehta <hemant29mehta@gmail.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
docs/platform/atoms/booker.mdx (1)

134-136: LGTM—clarifies invalid values and outcomes.

This addresses the earlier wording suggestion and clearly warns about "null"/empty strings causing 401s.

🧹 Nitpick comments (1)
docs/platform/atoms/booker.mdx (1)

134-136: Wording fix: avoid mixed contraction style.

Use "do not" (no contraction) for consistency with the preceding sentence.

-> When using `rescheduleUid` or `bookingUid` props, do **not** pass the string `"null"` or an empty string. If you don’t have a valid value, omit the prop or pass `null` (without quotes). Passing `"null"` or an empty string may result in a 401 Unauthorized error from the API.
+> When using `rescheduleUid` or `bookingUid` props, do **not** pass the string `"null"` or an empty string. If you do not have a valid value, omit the prop or pass `null` (without quotes). Passing `"null"` or an empty string may result in a 401 Unauthorized error from the API.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 64ccdc4 and e8c32ba.

📒 Files selected for processing (1)
  • docs/platform/atoms/booker.mdx (1 hunks)
🧰 Additional context used
🪛 LanguageTool
docs/platform/atoms/booker.mdx

[grammar] ~134-~134: There might be a mistake here.
Context: ... | > Note: > When using rescheduleUid or `bookingUi...

(QB_NEW_EN)

⏰ Context from checks skipped due to timeout of 180000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Install dependencies / Yarn install & cache

@github-actions github-actions bot removed the Stale label Sep 2, 2025
@Devanshusharma2005 Devanshusharma2005 marked this pull request as draft September 2, 2025 14:28
@hemantmm hemantmm marked this pull request as ready for review September 4, 2025 13:26
@dosubot dosubot bot added the bookings area: bookings, availability, timezones, double booking label Sep 4, 2025
@github-actions github-actions bot removed the Stale label Sep 5, 2025
@hemantmm
Copy link
Contributor Author

hemantmm commented Sep 7, 2025

@anikdhabal, I have attached a video. Can you have a look at it.

@github-actions github-actions bot added the Stale label Sep 9, 2025
@anikdhabal
Copy link
Contributor

cc @supalarry

@github-actions github-actions bot removed the Stale label Sep 11, 2025
@github-actions github-actions bot added the Stale label Sep 11, 2025
@github-actions github-actions bot removed the Stale label Sep 13, 2025
@github-actions github-actions bot added the Stale label Sep 14, 2025
@supalarry
Copy link
Contributor

Thank you for your PR Hemant! We appreciate your contribution.

I am not sure about the solution because:

  1. The original issue reports a problem when rescheduling, not when booking a meeting.
  2. The original issue does not report passing "null" as booking uid. Even if they did, I would lean towards that we don't necessarily need to check the value of the passed string so deeply because that is the responsibility of the user.

I am closing this issue for now because I asked original issue owner to provide more details.

@supalarry supalarry closed this Sep 15, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api area: API, enterprise API, access token, OAuth bookings area: bookings, availability, timezones, double booking 🐛 bug Something isn't working community Created by Linear-GitHub Sync Low priority Created by Linear-GitHub Sync platform Anything related to our platform plan size/M Stale

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Booker Atom component - 401 Error on request with rescheduleUid

4 participants