Skip to content

feat(wave): report client-side load/render errors to Faro#1927

Open
efstajas wants to merge 1 commit into
mainfrom
feat/client-error-faro-reporting
Open

feat(wave): report client-side load/render errors to Faro#1927
efstajas wants to merge 1 commit into
mainfrom
feat/client-error-faro-reporting

Conversation

@efstajas

Copy link
Copy Markdown
Contributor

Problem

Users have reported seeing a full-page Error 500 ("Something went wrong on our end" πŸ’€) when viewing an issue on the contributor dashboard β€” the screen SingleIssueError renders when page.status === 500.

That status comes from an unexpected error thrown in a client-side load function (e.g. a zod schema.parse failure in parseRes when a wave API response doesn't match its DTO β€” the backend returns a clean 200, so there's nothing in the backend logs). The frontend ships Grafana Faro, but none of these 500s show up in it: SvelteKit catches errors thrown in load/rendering, so they never reach window.onerror / unhandledrejection, which is all Faro's default web instrumentation observes. The result is a client-side observability blind spot β€” exactly the crashes users hit are the ones we can't see.

Fix

  • Add src/hooks.client.ts with a handleError hook. SvelteKit only calls this for unexpected errors (expected error(...) throws like 404s are handled directly and never reach it), so everything that arrives is a genuine crash worth reporting. Each is forwarded to Faro tagged with route, url, and status.
  • Capture the Faro instance in faro-manager.ts and expose a guarded pushError(error, context) helper. It no-ops when Faro isn't initialized (user hasn't consented to monitoring, or PUBLIC_FARO_ENABLED is off), so it's always safe to call.

Notes

This only adds reporting β€” it doesn't change anything users see (SvelteKit's default error message is preserved). It doesn't fix the underlying issue-view 500; it makes that error (and any future client-side load/render crash) visible in monitoring with its stack and route so the root cause can be diagnosed. Errors land in Loki as service_name="app", kind="exception".

Testing

  • npm run check β€” 0 errors.
  • prettier + eslint clean on changed files.

SvelteKit catches errors thrown in load functions and during rendering,
surfacing them to users as a full-page 500. Because they're caught, they
never reach window.onerror / unhandledrejection β€” the only thing Faro's
default web instrumentation observes β€” so these crashes were invisible in
monitoring (e.g. a zod parse failure in a wave API response throwing inside
an issue-page load).

Add a client handleError hook that forwards these unexpected errors to Faro
via a new guarded pushError helper, tagged with route, url and status. The
helper no-ops when Faro isn't initialized (no monitoring consent, or
PUBLIC_FARO_ENABLED off), so it's always safe to call.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds client-side crash reporting for SvelteKit load/render errors (which are normally swallowed before reaching window.onerror) by routing them through the app’s existing Grafana Faro integration, improving observability of user-facing β€œ500” error screens in the Wave UI.

Changes:

  • Introduces a client handleError hook to forward unexpected client-side errors to Faro with route/url/status context.
  • Captures the initialized Faro instance in faro-manager.ts and exposes a guarded pushError() helper.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
src/lib/utils/faro/faro-manager.ts Stores the Faro instance and adds a safe helper to push exceptions when monitoring is enabled.
src/hooks.client.ts Adds SvelteKit client handleError hook to report unexpected load/render crashes to Faro with route metadata.

πŸ’‘ Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 7 to 13
export const init = () => {
const FARO_ENABLED = getOptionalEnvVar('PUBLIC_FARO_ENABLED', false, null);
const FARO_ENVIRONMENT = getOptionalEnvVar('PUBLIC_FARO_ENVIRONMENT', false, null);

if (FARO_ENABLED === 'true' && FARO_ENVIRONMENT) {
initializeFaro({
faro = initializeFaro({
url: 'https://faro-collector-prod-eu-west-2.grafana.net/collect/0a4519657ebc92ca47d9271be5503b63',
Comment thread src/hooks.client.ts
Comment on lines +16 to +23
export const handleError: HandleClientError = ({ error, event, status, message }) => {
const reported = error instanceof Error ? error : new Error(message);

pushError(reported, {
route: event.route.id ?? 'unknown',
url: event.url.pathname,
status: String(status),
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants