From 29d90b5e71ee3839e6dbe0bc3b53a8002c3b8053 Mon Sep 17 00:00:00 2001 From: ERP-System Date: Mon, 8 Jun 2026 16:23:29 +0400 Subject: [PATCH] fix(vendor): stop detail route crashing when vendor fetch fails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The vendor detail page and layout called api.vendors.getById without a try/catch. The API client throws ApiError on any non-2xx, so a 404 (missing vendor), 401, or 5xx during SSR threw out of the server component and white-screened the whole route with a generic "server-side exception" — the existing `if (!vendor)` fallback was never reached. Guard both fetches: log the error and degrade gracefully (page shows "Vendor not found", layout renders chrome with a fallback title). Co-Authored-By: Claude Opus 4.8 (1M context) --- .../(authenticated)/purchase/vendor/[id]/layout.tsx | 11 +++++++++-- .../app/(authenticated)/purchase/vendor/[id]/page.tsx | 11 +++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/apps/dashboard/app/(authenticated)/purchase/vendor/[id]/layout.tsx b/apps/dashboard/app/(authenticated)/purchase/vendor/[id]/layout.tsx index 29bac15..1112e75 100644 --- a/apps/dashboard/app/(authenticated)/purchase/vendor/[id]/layout.tsx +++ b/apps/dashboard/app/(authenticated)/purchase/vendor/[id]/layout.tsx @@ -10,8 +10,15 @@ export default async function layout(props: { }) { const { id } = await props.params const api = await getServerApi() - const response = (await api.vendors.getById(id)) as { data?: Record } - const vendor = response?.data + // Guard the fetch: a failed request (404/401/5xx) must not throw and crash + // the whole route — render the chrome with a fallback title instead. + let vendor: Record | undefined + try { + const response = (await api.vendors.getById(id)) as { data?: Record } + vendor = response?.data + } catch (err) { + console.error(`Failed to load vendor ${id} (layout):`, err) + } const company = vendor?.company_name as string | undefined const fullName = [vendor?.first_name, vendor?.last_name].filter(Boolean).join(" ").trim() diff --git a/apps/dashboard/app/(authenticated)/purchase/vendor/[id]/page.tsx b/apps/dashboard/app/(authenticated)/purchase/vendor/[id]/page.tsx index f8739ee..aaeb81e 100644 --- a/apps/dashboard/app/(authenticated)/purchase/vendor/[id]/page.tsx +++ b/apps/dashboard/app/(authenticated)/purchase/vendor/[id]/page.tsx @@ -6,8 +6,15 @@ export default async function VendorDetailPage(props: { params: Promise<{ id: st const api = await getServerApi() // The OpenAPI schema doesn't yet describe GET /api/vendors/{id} (only PUT/DELETE), // so cast through `any` here until the schema is regenerated. - const response = (await api.vendors.getById(id)) as { data?: Record } - const vendor = response?.data + // Guard the fetch: a failed request (404/401/5xx) must degrade gracefully + // instead of throwing and white-screening the whole route. + let vendor: Record | undefined + try { + const response = (await api.vendors.getById(id)) as { data?: Record } + vendor = response?.data + } catch (err) { + console.error(`Failed to load vendor ${id}:`, err) + } if (!vendor) { return
Vendor not found.