Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/shared/errors.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
/**
* Thrown when an error is caused by user input rather than a system failure.
* These are intentionally excluded from Sentry to avoid noise.
*/
export class UserFacingError extends Error {
constructor(message: string) {
super(message)
this.name = 'UserFacingError'
}
}

export function isErrorWithMessage(error: unknown): error is Error {
return error !== undefined && error !== null && typeof error === 'object' && 'message' in error
}
Expand Down
4 changes: 4 additions & 0 deletions src/shared/thirdweb/emailAuth.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { inAppWallet, preAuthenticate } from 'thirdweb/wallets'
import { UserFacingError, isErrorWithMessage } from '../errors'
import { getThirdwebClient } from './client'

// Store the wallet instance for reuse
Expand Down Expand Up @@ -81,6 +82,9 @@ export const verifyEmailOTPAndConnect = async (email: string, verificationCode:
return account
} catch (error) {
console.error('[Thirdweb] Error verifying OTP:', error)
if (isErrorWithMessage(error) && /verify|invalid|expired/i.test(error.message)) {
throw new UserFacingError(error.message)
}
throw error
}
}
Expand Down
12 changes: 7 additions & 5 deletions src/shared/utils/errorHandler.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { captureException } from '@sentry/react'
import { TrackingEvents } from '../../modules/analytics/types'
import { isErrorWithMessage } from '../errors'
import { UserFacingError, isErrorWithMessage } from '../errors'
import { trackEvent } from './analytics'
import { ErrorContext, HandleErrorOptions } from './errorHandler.types'

Expand All @@ -11,10 +11,12 @@ const handleError = (error: unknown, context: string, options?: HandleErrorOptio
console.error(`${context}:`, errorMessage)
}

captureException(error, {
tags: options?.sentryTags,
extra: options?.sentryExtra
})
if (!options?.skipSentry && !(error instanceof UserFacingError)) {
captureException(error, {
tags: options?.sentryTags,
extra: options?.sentryExtra
})
}

if (!options?.skipTracking) {
const trackingEvent = (options?.trackingEvent as TrackingEvents) || TrackingEvents.LOGIN_ERROR
Expand Down
1 change: 1 addition & 0 deletions src/shared/utils/errorHandler.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,5 +71,6 @@ export interface HandleErrorOptions {
sentryExtra?: SentryExtra
skipLogging?: boolean
skipTracking?: boolean
skipSentry?: boolean
trackingEvent?: string
}