···5252 const str = String(e)
5353 return str.includes('Bad token scope') || str.includes('Bad token method')
5454}
5555+5656+/**
5757+ * Intended to capture "User cancelled" or "Crop cancelled" errors
5858+ * that we often get from expo modules such expo-image-crop-tool
5959+ *
6060+ * The exact name has changed in the past so let's just see if the string
6161+ * contains "cancel"
6262+ */
6363+export function isCancelledError(e: unknown) {
6464+ const str = String(e).toLowerCase()
6565+ return str.includes('cancel')
6666+}
+13-5
src/screens/Onboarding/StepProfile/index.tsx
···1515import {getDataUriSize} from '#/lib/media/util'
1616import {useRequestNotificationsPermission} from '#/lib/notifications/notifications'
1717import {logEvent, useGate} from '#/lib/statsig/statsig'
1818+import {isCancelledError} from '#/lib/strings/errors'
1919+import {logger} from '#/logger'
1820import {isNative, isWeb} from '#/platform/detection'
1921import {
2022 DescriptionText,
···184186 if (!image) return
185187186188 if (!isWeb) {
187187- image = await openCropper({
188188- imageUri: image.path,
189189- shape: 'circle',
190190- aspectRatio: 1 / 1,
191191- })
189189+ try {
190190+ image = await openCropper({
191191+ imageUri: image.path,
192192+ shape: 'circle',
193193+ aspectRatio: 1 / 1,
194194+ })
195195+ } catch (e) {
196196+ if (!isCancelledError(e)) {
197197+ logger.error('Failed to crop avatar in onboarding', {error: e})
198198+ }
199199+ }
192200 }
193201 image = await compressIfNeeded(image, 1000000)
194202
+2-1
src/state/gallery.ts
···1717import {openCropper} from '#/lib/media/picker'
1818import {type PickerImage} from '#/lib/media/picker.shared'
1919import {getDataUriSize} from '#/lib/media/util'
2020+import {isCancelledError} from '#/lib/strings/errors'
2021import {isNative} from '#/platform/detection'
21222223export type ImageTransformation = {
···143144 },
144145 }
145146 } catch (e) {
146146- if (e instanceof Error && e.message.includes('User cancelled')) {
147147+ if (!isCancelledError(e)) {
147148 return img
148149 }
149150
+4-3
src/view/com/util/UserAvatar.tsx
···2626import {type PickerImage} from '#/lib/media/picker.shared'
2727import {makeProfileLink} from '#/lib/routes/links'
2828import {sanitizeDisplayName} from '#/lib/strings/display-names'
2929+import {isCancelledError} from '#/lib/strings/errors'
2930import {sanitizeHandle} from '#/lib/strings/handles'
3031import {logger} from '#/logger'
3132import {isAndroid, isNative, isWeb} from '#/platform/detection'
···407408 setRawImage(await createComposerImage(item))
408409 editImageDialogControl.open()
409410 }
410410- } catch (e: any) {
411411+ } catch (e) {
411412 // Don't log errors for cancelling selection to sentry on ios or android
412412- if (!String(e).toLowerCase().includes('cancel')) {
413413- logger.error('Failed to crop banner', {error: e})
413413+ if (!isCancelledError(e)) {
414414+ logger.error('Failed to crop avatar', {error: e})
414415 }
415416 }
416417 }, [
+4-2
src/view/com/util/UserBanner.tsx
···1212import {compressIfNeeded} from '#/lib/media/manip'
1313import {openCamera, openCropper, openPicker} from '#/lib/media/picker'
1414import {type PickerImage} from '#/lib/media/picker.shared'
1515+import {isCancelledError} from '#/lib/strings/errors'
1516import {logger} from '#/logger'
1617import {isAndroid, isNative} from '#/platform/detection'
1718import {
···8788 setRawImage(await createComposerImage(items[0]))
8889 editImageDialogControl.open()
8990 }
9090- } catch (e: any) {
9191- if (!String(e).includes('Canceled')) {
9191+ } catch (e) {
9292+ // Don't log errors for cancelling selection to sentry on ios or android
9393+ if (!isCancelledError(e)) {
9294 logger.error('Failed to crop banner', {error: e})
9395 }
9496 }