fix: router failing to match channel route when 'First Channel After Login' starts with a hash
Proposed changes (including videos or screenshots)
This PR fixes an issue where the router failed to match the channel route when the “First Channel After Login” setting started with a hash (#).
Because URLs interpret # as the beginning of a fragment, the browser stops parsing the path at that point, causing the router to treat the channel name as invalid. As a result, the client loaded an not-found error page, and the sidebar did not appear.
This fix removes the leading hash before routing, ensuring the channel is resolved correctly, and the client loads normally after login.
Issue(s)
Steps to test or reproduce
Further comments
Summary by CodeRabbit
-
Bug Fixes
- Fixed "First Channel After Login" redirect so channel names starting with "#" are normalized and users are routed correctly.
- Redirect now triggers only for home routes and runs once per session to avoid repeated navigation.
-
Tests
- Added comprehensive tests covering redirect behavior across home, root, non-home routes, empty setting, and re-renders.
✏️ Tip: You can customize this high-level summary in your review settings.
Looks like this PR is ready to merge! 🎉 If you have any trouble, please check the PR guidelines
🦋 Changeset detected
Latest commit: e29a17764fb8a1d0e26fb70a18ad894553315bf8
The changes in this PR will be included in the next version bump.
This PR includes changesets to release 41 packages
| Name | Type |
|---|---|
| @rocket.chat/meteor | Patch |
| @rocket.chat/core-typings | Patch |
| @rocket.chat/rest-typings | Patch |
| @rocket.chat/uikit-playground | Patch |
| @rocket.chat/api-client | Patch |
| @rocket.chat/apps | Patch |
| @rocket.chat/core-services | Patch |
| @rocket.chat/cron | Patch |
| @rocket.chat/ddp-client | Patch |
| @rocket.chat/freeswitch | Patch |
| @rocket.chat/fuselage-ui-kit | Patch |
| @rocket.chat/gazzodown | Patch |
| @rocket.chat/http-router | Patch |
| @rocket.chat/livechat | Patch |
| @rocket.chat/model-typings | Patch |
| @rocket.chat/ui-avatar | Patch |
| @rocket.chat/ui-client | Patch |
| @rocket.chat/ui-contexts | Patch |
| @rocket.chat/ui-voip | Patch |
| @rocket.chat/web-ui-registration | Patch |
| @rocket.chat/account-service | Patch |
| @rocket.chat/authorization-service | Patch |
| @rocket.chat/ddp-streamer | Patch |
| @rocket.chat/omnichannel-transcript | Patch |
| @rocket.chat/presence-service | Patch |
| @rocket.chat/queue-worker | Patch |
| @rocket.chat/stream-hub-service | Patch |
| @rocket.chat/federation-matrix | Patch |
| @rocket.chat/license | Patch |
| @rocket.chat/media-calls | Patch |
| @rocket.chat/omnichannel-services | Patch |
| @rocket.chat/pdf-worker | Patch |
| @rocket.chat/presence | Patch |
| rocketchat-services | Patch |
| @rocket.chat/models | Patch |
| @rocket.chat/network-broker | Patch |
| @rocket.chat/omni-core-ee | Patch |
| @rocket.chat/mock-providers | Patch |
| @rocket.chat/ui-video-conf | Patch |
| @rocket.chat/instance-status | Patch |
| @rocket.chat/omni-core | Patch |
Not sure what this means? Click here to learn what changesets are.
Click here if you're a maintainer who wants to add another changeset to this PR
Walkthrough
Normalize the First_Channel_After_Login setting by stripping a leading # into roomName, block names that start with # or ?, and perform a one-time redirect to /channel/{roomName} in LayoutWithSidebar and LayoutWithSidebarV2; add tests and a patch changeset documenting the fix.
Changes
| Cohort / File(s) | Change Summary |
|---|---|
LayoutWithSidebar component & tests apps/meteor/client/views/root/MainLayout/LayoutWithSidebar.tsx, apps/meteor/client/views/root/MainLayout/LayoutWithSidebar.spec.tsx |
Use useSetting<string>('First_Channel_After_Login', ''), derive roomName by stripping a leading # and trimming, require non-empty roomName, reject names starting with invalid prefixes (#, ?), redirect to /channel/{roomName}, update useEffect dependencies to include roomName, and add tests covering normalization, redirects from / and /home, non-redirect scenarios, and single-redirect behavior across re-renders. |
LayoutWithSidebarV2 component & tests apps/meteor/client/views/root/MainLayout/LayoutWithSidebarV2.tsx, apps/meteor/client/views/root/MainLayout/LayoutWithSidebarV2.spec.tsx |
Mirror V1 changes: add INVALID_ROOM_NAME_PREFIXES, compute roomName (strip leading #, trim), guard against invalid prefixes, redirect to /channel/{roomName}, update effect deps, and add tests with mocked UI contexts/components validating the same behaviors and edge cases. |
Changeset .changeset/sixty-bikes-know.md |
Add patch changeset noting the fix for First_Channel_After_Login values that began with # (and other invalid prefixes), preventing client routing failures and ensuring correct redirection to the intended channel. |
Estimated code review effort
🎯 3 (Moderate) | ⏱️ ~20-30 minutes
- Pay attention to:
- useEffect dependency arrays in both components to ensure redirects trigger appropriately and only once.
- Correctness of
roomNamenormalization for edge cases (e.g.,"#", strings with surrounding whitespace, empty values). - The invalid-prefix check logic and its interaction with the leading-
#stripping. - Tests' routing mocks to confirm navigation assertions reflect actual push behavior.
Suggested labels
stat: ready to merge, stat: QA assured
Suggested reviewers
- pierre-lehnen-rc
- tassoevan
Poem
🐰 I nibbled a
#and set things right,
One gentle redirect, no frantic plight,
Tests hopped in line and gave a cheer,
Sidebar's back — I munch a carrot near 🥕
Pre-merge checks and finishing touches
✅ Passed checks (5 passed)
| Check name | Status | Explanation |
|---|---|---|
| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled. |
| Title check | ✅ Passed | The title accurately describes the main fix: handling the hash symbol issue in the 'First Channel After Login' setting for correct routing. |
| Linked Issues check | ✅ Passed | The PR addresses the core requirement from SUP-916 by fixing routing when First_Channel_After_Login starts with # and preventing other invalid prefixes (?, @) from breaking navigation. |
| Out of Scope Changes check | ✅ Passed | All changes are directly related to fixing the First_Channel_After_Login routing issue: validation logic in components, comprehensive test coverage, and changeset documentation. |
| Docstring Coverage | ✅ Passed | No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. |
✨ Finishing touches
- [ ] 📝 Generate docstrings
🧪 Generate unit tests (beta)
- [ ] Create PR with unit tests
- [ ] Post copyable unit tests in a comment
- [ ] Commit unit tests in branch
fix/missing-sidebar-invalid-first-channel
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.
Comment @coderabbitai help to get the list of available commands and usage tips.
📦 Docker Image Size Report
📈 Changes 
| Service | Current | Baseline | Change | Percent |
|---|---|---|---|---|
| sum of all images | 1.2GiB | 1.2GiB | +12MiB | |
| rocketchat | 360MiB | 349MiB | +12MiB | |
| omnichannel-transcript-service | 132MiB | 132MiB | -24B | |
| queue-worker-service | 132MiB | 132MiB | +64B | |
| ddp-streamer-service | 126MiB | 126MiB | -536B | |
| account-service | 113MiB | 113MiB | +454B | |
| stream-hub-service | 111MiB | 111MiB | -291B | |
| presence-service | 111MiB | 111MiB | -657B | |
| authorization-service | 111MiB | 111MiB | -1.1KiB |
📊 Historical Trend
---
config:
theme: "dark"
xyChart:
width: 900
height: 400
---
xychart
title "Image Size Evolution by Service (Last 30 Days + This PR)"
x-axis ["11/15 22:28", "11/16 01:28", "11/17 23:50", "11/18 22:53", "11/19 23:02", "11/21 16:49", "11/24 17:34", "11/27 22:32", "11/28 19:05", "12/01 23:01", "12/02 21:57", "12/03 21:00", "12/04 18:17", "12/05 21:56", "12/08 20:15", "12/09 22:17", "12/10 23:26", "12/11 01:16", "12/11 10:47 (PR)"]
y-axis "Size (GB)" 0 --> 0.5
line "account-service" [0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11]
line "authorization-service" [0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11]
line "ddp-streamer-service" [0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12]
line "omnichannel-transcript-service" [0.14, 0.14, 0.14, 0.14, 0.14, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13]
line "presence-service" [0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11]
line "queue-worker-service" [0.14, 0.14, 0.14, 0.14, 0.14, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13]
line "rocketchat" [0.36, 0.36, 0.35, 0.35, 0.35, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.35]
line "stream-hub-service" [0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11]
Statistics (last 18 days):
- 📊 Average: 1.5GiB
- ⬇️ Minimum: 1.2GiB
- ⬆️ Maximum: 1.6GiB
- 🎯 Current PR: 1.2GiB
ℹ️ About this report
This report compares Docker image sizes from this build against the develop baseline.
-
Tag:
pr-37656 -
Baseline:
develop - Timestamp: 2025-12-11 10:47:56 UTC
- Historical data points: 18
Updated: Thu, 11 Dec 2025 10:47:56 GMT
Codecov Report
:x: Patch coverage is 57.14286% with 6 lines in your changes missing coverage. Please review.
:white_check_mark: Project coverage is 68.73%. Comparing base (99dcf8c) to head (e29a177).
:warning: Report is 1 commits behind head on develop.
Additional details and impacted files
@@ Coverage Diff @@
## develop #37656 +/- ##
===========================================
+ Coverage 67.70% 68.73% +1.03%
===========================================
Files 3452 3367 -85
Lines 113975 114342 +367
Branches 20941 20709 -232
===========================================
+ Hits 77166 78595 +1429
+ Misses 34680 33637 -1043
+ Partials 2129 2110 -19
| Flag | Coverage Δ | |
|---|---|---|
| e2e | 57.25% <57.14%> (-0.04%) |
:arrow_down: |
| e2e-api | 42.28% <ø> (+<0.01%) |
:arrow_up: |
Flags with carried forward coverage won't be shown. Click here to find out more.
:rocket: New features to boost your workflow:
- :snowflake: Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
- :package: JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.
Instead of only checking for
#, maybe we should sanitize the string following the existing rules for channel names? For example a user could add!channelto the firstChannelAfterLogin, that would probably still cause the same bug
Hey @MartinSchoeler,
Based on your suggestion, I explored a few possible approaches and here’s what I found:
-
Slugified channel names When special characters are allowed in channel names, we store:
- the slugified value in the
namefield, and - the user-provided name in the
fnamefield.
The client cannot reliably derive
namefromfname, because if a channel already exists with the same slugified name, the backend appends a suffix (e.g.slugified(fname)-<number>). This makes the finalnameunpredictable on the client side. - the slugified value in the
-
Why the page without a sidebar appears The page without the sidebar is the global not-found page. This happens specifically when the channel name starts with
@or?:-
@channelNameresults in/channel/#channelName- Path:
/channel - Fragment:
#channelName
- Path:
-
?channelNameresults in/channel/?channelName- Path:
/channel - Query:
?channelName
- Path:
Since we don’t have any routes defined for the path
/channel, these cases fall through to the global not-found page.In all other cases, routing resolves to the room routes. If the room does not exist, we correctly show the room not-found page along with the sidebar.
-
-
If we explicitly handle the two edge cases where the channel name starts with
@or?, this issue should be fully resolved.