From c3dec0bf503827392abb284cade06a4f81b3568e Mon Sep 17 00:00:00 2001 From: Samuel Newman Date: Sat, 25 Jul 2026 16:24:14 +0300 Subject: [PATCH] fix: stop grouping all signup failures into one sentry issue Fixes APP-S3WR Co-Authored-By: Claude Fable 5 --- src/analytics/metrics/types.ts | 4 +++ src/screens/Signup/StepCaptcha/index.tsx | 16 +++------- src/screens/Signup/state.ts | 40 ++++++++++++++++++------ 3 files changed, 39 insertions(+), 21 deletions(-) diff --git a/src/analytics/metrics/types.ts b/src/analytics/metrics/types.ts index 1d1c88baca..6d7412aadc 100644 --- a/src/analytics/metrics/types.ts +++ b/src/analytics/metrics/types.ts @@ -103,6 +103,10 @@ export type Events = { } 'signup:captchaSuccess': {} 'signup:captchaFailure': {} + 'signup:captchaBackPress': {} + 'signup:createAccountFailure': { + reason: string + } 'signup:fieldError': { field: string errorCount: number diff --git a/src/screens/Signup/StepCaptcha/index.tsx b/src/screens/Signup/StepCaptcha/index.tsx index 2c5d88f2c8..43e536c7ae 100644 --- a/src/screens/Signup/StepCaptcha/index.tsx +++ b/src/screens/Signup/StepCaptcha/index.tsx @@ -127,23 +127,17 @@ function StepCaptchaInner({ value: _(msg`Error receiving captcha response.`), }) ax.metric('signup:captchaFailure', {}) - logger.error('Signup Flow Error', { - registrationHandle: state.handle, - error, + logger.error('Signup: captcha response error', { + safeMessage: error, }) }, - [_, ax, dispatch, state.handle], + [_, ax, dispatch], ) const onBackPress = useCallback(() => { - logger.error('Signup Flow Error', { - errorMessage: - 'User went back from captcha step. Possibly encountered an error.', - registrationHandle: state.handle, - }) - + ax.metric('signup:captchaBackPress', {}) dispatch({type: 'prev'}) - }, [dispatch, state.handle]) + }, [ax, dispatch]) return ( <> diff --git a/src/screens/Signup/state.ts b/src/screens/Signup/state.ts index a154195124..95b3185758 100644 --- a/src/screens/Signup/state.ts +++ b/src/screens/Signup/state.ts @@ -8,7 +8,7 @@ import {useLingui} from '@lingui/react/macro' import * as EmailValidator from 'email-validator' import {DEFAULT_SERVICE} from '#/lib/constants' -import {cleanError} from '#/lib/strings/errors' +import {cleanError, isNetworkError} from '#/lib/strings/errors' import {createFullHandle} from '#/lib/strings/handles' import {getAge} from '#/lib/strings/time' import {useSessionApi} from '#/state/session' @@ -255,6 +255,25 @@ export const SignupContext = createContext({} as IContext) SignupContext.displayName = 'SignupContext' export const useSignupContext = () => useContext(SignupContext) +/** + * Returns a PII-free name for expected signup failures, or undefined if the + * failure is unexpected and should be reported to Sentry. + */ +function classifyExpectedSignupError(e: unknown): string | undefined { + if (e instanceof ComAtprotoServerCreateAccount.InvalidHandleError) + return 'InvalidHandle' + if (e instanceof ComAtprotoServerCreateAccount.HandleNotAvailableError) + return 'HandleNotAvailable' + if (e instanceof ComAtprotoServerCreateAccount.InvalidPasswordError) + return 'InvalidPassword' + if (e instanceof ComAtprotoServerCreateAccount.UnsupportedDomainError) + return 'UnsupportedDomain' + /* the server sends no typed error for this case */ + if (String(e).includes('Email already taken')) return 'EmailTaken' + if (isNetworkError(e)) return 'NetworkError' + return undefined +} + export function useSubmitSignup() { const ax = useAnalytics() const {t: l} = useLingui() @@ -300,10 +319,7 @@ export function useSubmitSignup() { !state.pendingSubmit?.verificationCode ) { dispatch({type: 'setStep', value: SignupStep.CAPTCHA}) - ax.logger.error('Signup Flow Error', { - errorMessage: 'Verification captcha code was not set.', - registrationHandle: state.handle, - }) + ax.logger.error('Signup: captcha code missing at submit', {}) return dispatch({ type: 'setError', value: l`Please complete the verification captcha.`, @@ -362,14 +378,18 @@ export function useSubmitSignup() { }) dispatch({type: 'setStep', value: isHandleError ? 2 : 1}) - ax.logger.error('Signup Flow Error', { - errorMessage: error, - registrationHandle: state.handle, - }) + const expected = classifyExpectedSignupError(e) + if (expected) { + ax.metric('signup:createAccountFailure', {reason: expected}) + } else { + ax.logger.error('Signup: unexpected createAccount failure', { + safeMessage: e, + }) + } } finally { dispatch({type: 'setIsLoading', value: false}) } }, - [l, ax.logger, createAccount, onboardingDispatch], + [l, ax, createAccount, onboardingDispatch], ) }