From 098cc7c754062b7bc9ad5bd55c2b3b49dc1751df Mon Sep 17 00:00:00 2001 From: Daniel Heene Date: Fri, 9 Oct 2026 11:54:03 +0200 Subject: [PATCH] fix(umami): silence expected connection failures when Umami is unreachable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In E2E and test environments NEXT_PUBLIC_UMAMI_URL points to localhost:3002 which does not exist. Catch the upstream fetch error in the /stats proxy route and return 204 silently. Remove console.error calls from UmamiWidget.data.ts login/verify/fetch paths — the widget already handles null returns gracefully so the errors were pure noise with no actionable information. --- app/(frontend)/stats/[...path]/route.ts | 20 +++++++++++++------- src/widgets/UmamiWidget/UmamiWidget.data.ts | 9 +++------ 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/app/(frontend)/stats/[...path]/route.ts b/app/(frontend)/stats/[...path]/route.ts index 4a58027a..8c1fea75 100644 --- a/app/(frontend)/stats/[...path]/route.ts +++ b/app/(frontend)/stats/[...path]/route.ts @@ -28,13 +28,19 @@ export async function POST( const headers = new Headers(req.headers) headers.delete('host') - const upstream = await fetch(destination, { - method: 'POST', - headers, - body: req.body, - // @ts-ignore -- duplex is required for streaming request bodies in Node fetch - duplex: 'half', - }) + let upstream: Response + try { + upstream = await fetch(destination, { + method: 'POST', + headers, + body: req.body, + // @ts-ignore -- duplex is required for streaming request bodies in Node fetch + duplex: 'half', + }) + } catch { + // Umami unreachable (e.g. in E2E/test environments) — fail silently. + return new NextResponse(null, { status: 204 }) + } return new NextResponse(upstream.body, { status: upstream.status, diff --git a/src/widgets/UmamiWidget/UmamiWidget.data.ts b/src/widgets/UmamiWidget/UmamiWidget.data.ts index 525d0ae7..2762b942 100644 --- a/src/widgets/UmamiWidget/UmamiWidget.data.ts +++ b/src/widgets/UmamiWidget/UmamiWidget.data.ts @@ -20,8 +20,7 @@ const login = async (): Promise => { const data = await response.json() token = (data.token as string) ?? null - } catch (error) { - console.error('Error logging in to Umami:', error) + } catch { token = null } return token @@ -40,8 +39,7 @@ const verify = async (): Promise => { }) return response.ok - } catch (error) { - console.error('Error verifying token:', error) + } catch { return false } } @@ -97,8 +95,7 @@ const fetcher = async (url: URL | string): Promise = await set(url.toString(), json as T, CACHE_TTL_SECONDS) return json - } catch (error) { - console.error('Error fetching Umami data:', error) + } catch { return null } }