fix: stop grouping all signup failures into one sentry issue

Fixes APP-S3WR

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Samuel Newman
2026-07-25 16:24:14 +03:00
parent d5e335e575
commit c3dec0bf50
3 changed files with 39 additions and 21 deletions
+4
View File
@@ -103,6 +103,10 @@ export type Events = {
}
'signup:captchaSuccess': {}
'signup:captchaFailure': {}
'signup:captchaBackPress': {}
'signup:createAccountFailure': {
reason: string
}
'signup:fieldError': {
field: string
errorCount: number
+5 -11
View File
@@ -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 (
<>
+30 -10
View File
@@ -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<IContext>({} 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],
)
}