From 43beeae39d27b932dcde2435413d3359bc36ef9a Mon Sep 17 00:00:00 2001 From: Daniel Han Date: Fri, 22 May 2026 04:30:32 -0700 Subject: [PATCH] studio/frontend: friendlier 404 fallback for unknown routes (#5664) * studio/frontend: friendlier 404 fallback for unknown routes TanStack Router defaults to a bare "Not Found" string when no route matches. With Studio's root layout that string sits alone in the main content area while the sidebar still renders, which looks broken when the user hits a typo'd path, a stale share link, or a chat URL with an extra path segment. Provide a small DefaultNotFound component to createRouter: sloth mascot, "Page not found" heading, the offending pathname, and a Back to chat button. Studio chrome continues to render around it, so the user gets the same sidebar nav for free. Resolves #5663. * studio/frontend: 404 fallback uses useRouterState + URL-encoded sloth path Address review feedback on #5664: - Read pathname via useRouterState({ select: s => s.location.pathname }) instead of window.location.pathname. Matches the pattern already used in __root.tsx, drops the window-typeof guard, and stays consistent with the router store on subsequent client navigations. - URL-encode the sloth mascot src so the space-containing path resolves cleanly without relying on the browser to encode it. - Add break-all on the pathname paragraph so long offending URLs wrap instead of pushing the card wider than the viewport. --------- Co-authored-by: danielhanchen --- studio/frontend/src/app/router.tsx | 32 ++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/studio/frontend/src/app/router.tsx b/studio/frontend/src/app/router.tsx index d26d8b9dee..c7bc0440bd 100644 --- a/studio/frontend/src/app/router.tsx +++ b/studio/frontend/src/app/router.tsx @@ -1,7 +1,8 @@ // SPDX-License-Identifier: AGPL-3.0-only // Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0 -import { createRouter } from "@tanstack/react-router"; +import { Link, createRouter, useRouterState } from "@tanstack/react-router"; +import { Button } from "@/components/ui/button"; import { Route as rootRoute } from "./routes/__root"; import { Route as dataRecipesRoute } from "./routes/data-recipes"; import { Route as dataRecipeRoute } from "./routes/data-recipes.$recipeId"; @@ -29,7 +30,34 @@ const routeTree = rootRoute.addChildren([ dataRecipeRoute, ]); -export const router = createRouter({ routeTree }); +function DefaultNotFound() { + const pathname = useRouterState({ select: (s) => s.location.pathname }); + return ( +
+ Sloth mascot +
+

+ Page not found +

+

+ {pathname} does not exist. +

+
+ +
+ ); +} + +export const router = createRouter({ + routeTree, + defaultNotFoundComponent: DefaultNotFound, +}); declare module "@tanstack/react-router" { interface Register {