From 18fa798ff3b9ba27d9c668e7a855ce22e8361a76 Mon Sep 17 00:00:00 2001 From: waleed Date: Fri, 3 Jul 2026 14:16:31 -0700 Subject: [PATCH] fix(chat): fail-safe to noindex if the deployment lookup errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit generateMetadata queried the DB with no error handling, unlike the identical query in api/chat/[identifier]/route.ts (which already wraps it in try/catch). There's no error.tsx under app/(interfaces)/chat/ — metadata resolution errors aren't caught by route-segment error boundaries at all, only the root global-error.tsx — so a DB hiccup during this lookup would take the whole page down to a generic error page instead of just failing to determine indexability. Catches the error, logs it, and defaults to noindex: if we can't confirm the deployment is safely public, that's the correct SEO default anyway, not a reason to crash the request. Flagged by Cursor Bugbot on #5388 (already merged); this ships the fix as a standalone follow-up since the underlying code is already live. --- .../(interfaces)/chat/[identifier]/page.tsx | 31 +++++++++++++++---- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/apps/sim/app/(interfaces)/chat/[identifier]/page.tsx b/apps/sim/app/(interfaces)/chat/[identifier]/page.tsx index e1a8c32b17d..f55345cbbbc 100644 --- a/apps/sim/app/(interfaces)/chat/[identifier]/page.tsx +++ b/apps/sim/app/(interfaces)/chat/[identifier]/page.tsx @@ -1,15 +1,26 @@ import { db } from '@sim/db' import { chat } from '@sim/db/schema' +import { createLogger } from '@sim/logger' +import { getErrorMessage } from '@sim/utils/errors' import { and, eq, isNull } from 'drizzle-orm' import type { Metadata } from 'next' import ChatClient from '@/app/(interfaces)/chat/[identifier]/chat' import { OfficeEmbedInit } from '@/app/(interfaces)/chat/[identifier]/office-embed-init' +const logger = createLogger('ChatMetadata') + /** * Only fully public, active deployments are indexable. Auth-gated (password, * email, SSO) and inactive/nonexistent chats are noindexed at the page level * so Google never indexes an auth wall — narrower than blocking `/chat/` * entirely in robots.ts, which would also hide genuinely public deployments. + * + * Errors from the lookup fail toward noindex rather than throwing: unlike + * the identical query in app/api/chat/[identifier]/route.ts (which must + * surface failures to the caller), a metadata resolution error has no + * error.tsx boundary in this route to catch it — throwing here would take + * the whole page down instead of just skipping indexability, and "can't + * confirm this is safe to index" should default to not indexing it anyway. */ export async function generateMetadata({ params, @@ -18,13 +29,21 @@ export async function generateMetadata({ }): Promise { const { identifier } = await params - const [deployment] = await db - .select({ authType: chat.authType, isActive: chat.isActive }) - .from(chat) - .where(and(eq(chat.identifier, identifier), isNull(chat.archivedAt))) - .limit(1) + let isIndexable = false + try { + const [deployment] = await db + .select({ authType: chat.authType, isActive: chat.isActive }) + .from(chat) + .where(and(eq(chat.identifier, identifier), isNull(chat.archivedAt))) + .limit(1) - const isIndexable = Boolean(deployment?.isActive && deployment.authType === 'public') + isIndexable = Boolean(deployment?.isActive && deployment.authType === 'public') + } catch (error) { + logger.error('Failed to resolve chat deployment for metadata', { + identifier, + error: getErrorMessage(error), + }) + } return { title: 'Chat',