diff --git a/packages/fern-docs/bundle/src/app/[host]/[domain]/[lang]/dynamic/not-found.tsx b/packages/fern-docs/bundle/src/app/[host]/[domain]/[lang]/dynamic/not-found.tsx index 549afcba54..f22190d09e 100644 --- a/packages/fern-docs/bundle/src/app/[host]/[domain]/[lang]/dynamic/not-found.tsx +++ b/packages/fern-docs/bundle/src/app/[host]/[domain]/[lang]/dynamic/not-found.tsx @@ -3,6 +3,7 @@ import "server-only"; import NotFoundContent from "@/components/NotFoundContent"; export const dynamic = "force-dynamic"; +export const runtime = "nodejs"; export default async function NotFound() { return ; diff --git a/packages/fern-docs/bundle/src/app/[host]/[domain]/[lang]/static/not-found.tsx b/packages/fern-docs/bundle/src/app/[host]/[domain]/[lang]/static/not-found.tsx index 549afcba54..f22190d09e 100644 --- a/packages/fern-docs/bundle/src/app/[host]/[domain]/[lang]/static/not-found.tsx +++ b/packages/fern-docs/bundle/src/app/[host]/[domain]/[lang]/static/not-found.tsx @@ -3,6 +3,7 @@ import "server-only"; import NotFoundContent from "@/components/NotFoundContent"; export const dynamic = "force-dynamic"; +export const runtime = "nodejs"; export default async function NotFound() { return ; diff --git a/packages/fern-docs/bundle/src/components/NotFoundContent/index.tsx b/packages/fern-docs/bundle/src/components/NotFoundContent/index.tsx index ecd2dfd113..5020ea9a0c 100644 --- a/packages/fern-docs/bundle/src/components/NotFoundContent/index.tsx +++ b/packages/fern-docs/bundle/src/components/NotFoundContent/index.tsx @@ -11,6 +11,53 @@ import { NotFound404Tracker } from "../analytics/NotFound404Tracker"; import ReturnHomeButton from "../ReturnHomeButton"; import { getRouteSuggestions, type RouteSuggestion } from "./get-route-suggestions"; +/** + * Generate fallback suggestions based on the requested path + * Returns parent paths as suggestions when server suggestions fail + */ +function generateFallbackSuggestions(requestedPath: string): RouteSuggestion[] { + if (!requestedPath || requestedPath === "/") { + return []; + } + + const normalizedPath = requestedPath.replace(/^\/+|\/+$/g, ""); + const segments = normalizedPath.split("/").filter((s) => s.length > 0); + + const suggestions: RouteSuggestion[] = []; + + for (let i = segments.length - 1; i > 0; i--) { + const parentPath = "/" + segments.slice(0, i).join("/"); + const title = segments + .slice(0, i) + .map((s) => s.charAt(0).toUpperCase() + s.slice(1).replace(/-/g, " ")) + .join(" › "); + + suggestions.push({ + slug: parentPath, + title: title, + href: parentPath, + score: 1 - (segments.length - i) * 0.2, + subtitle: "Parent section" + }); + + if (suggestions.length >= 3) { + break; + } + } + + if (suggestions.length < 3) { + suggestions.push({ + slug: "/", + title: "Home", + href: "/", + score: 0.1, + subtitle: "Return to homepage" + }); + } + + return suggestions; +} + export default function NotFoundContent() { const pathname = usePathname(); const [suggestedRoutes, setSuggestedRoutes] = useState([]); @@ -23,9 +70,17 @@ export default function NotFoundContent() { try { setIsLoading(true); const suggestions = await getRouteSuggestions(requestedPath); - setSuggestedRoutes(suggestions); + + if (suggestions.length > 0) { + setSuggestedRoutes(suggestions); + } else { + const fallbackSuggestions = generateFallbackSuggestions(requestedPath); + setSuggestedRoutes(fallbackSuggestions); + } } catch (error) { console.error("[NotFoundContent] Error loading suggestions:", error); + const fallbackSuggestions = generateFallbackSuggestions(requestedPath); + setSuggestedRoutes(fallbackSuggestions); } finally { setIsLoading(false); }