{"record":{"id":"c99f9de8bf8fedeb","repo":"expo/expo","slug":"failed-to-get-push-token-permission","errorCode":null,"errorMessage":"Failed to get push token permission!","messagePattern":"Failed to get push token permission!","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/notification-tester/src/registerForNotifications.ts","lineNumber":17,"sourceCode":"import Constants from 'expo-constants';\nimport {\n  getExpoPushTokenAsync,\n  getPermissionsAsync,\n  requestPermissionsAsync,\n} from 'expo-notifications';\n\nexport async function registerForPushNotificationsAsync() {\n  const { status: existingStatus } = await getPermissionsAsync();\n  let finalStatus = existingStatus;\n  if (existingStatus !== 'granted') {\n    const { status } = await requestPermissionsAsync();\n    finalStatus = status;\n  }\n  if (finalStatus !== 'granted') {\n    alert('Failed to get push token permission!');\n    throw new Error('Failed to get push token permission!');\n  }\n  // Learn more about projectId:\n  // https://docs.expo.dev/push-notifications/push-notifications-setup/#configure-projectid\n  // Here we use EAS projectId\n  const projectId = Constants?.expoConfig?.extra?.eas?.projectId ?? Constants?.easConfig?.projectId;\n  if (!projectId) {\n    throw new Error('Project ID not found');\n  }\n  const token = (\n    await getExpoPushTokenAsync({\n      projectId,\n    })\n  ).data;\n  return token;\n}\n","sourceCodeStart":1,"sourceCodeEnd":33,"githubUrl":"https://github.com/expo/expo/blob/b09195aac27c9e4a63daaf12dcb6f00b6b2e08ee/apps/notification-tester/src/registerForNotifications.ts#L1-L33","documentation":"Thrown by `registerForPushNotificationsAsync` in notification-tester after the user declined or the system denied notification permissions. The function first reads the existing permission status, requests if not granted, and if the final status is still not `'granted'` it alerts the user and throws. This halts token registration because a push token cannot be obtained without permission.","triggerScenarios":"The user denies the notification permission prompt, or `getPermissionsAsync`/`requestPermissionsAsync` return a status other than `'granted'` (e.g. `'denied'`, `'undetermined'` on iOS, blocked on Android 13+).","commonSituations":"First launch where the user taps 'Don't Allow'; the user previously denied and iOS won't re-prompt; Android 13+ runtime permission not granted; testing on a simulator that blocks notifications.","solutions":["Ask the user to enable notifications in OS Settings and re-launch, since iOS won't re-prompt after denial.","Gate the registration call behind a UI that explains the value before requesting permission (improves grant rate).","Wrap the call in try/catch so a denial degrades gracefully instead of crashing the app."],"exampleFix":"// before\nawait registerForPushNotificationsAsync(); // throws on denial, crashes flow\n\n// after\ntry {\n  await registerForPushNotificationsAsync();\n} catch (e) {\n  Alert.alert('Notifications disabled', 'Enable them in Settings to receive alerts.');\n}","handlingStrategy":"try-catch","validationCode":"import { getPermissionsAsync } from 'expo-notifications';\nasync function hasNotificationPermission(): Promise<boolean> {\n  const { status } = await getPermissionsAsync();\n  return status === 'granted';\n}","typeGuard":null,"tryCatchPattern":"try {\n  await registerForPushNotificationsAsync();\n} catch (e) {\n  if (/permission/i.test(e.message)) {\n    Alert.alert('Notifications disabled', 'Enable them in Settings.');\n  } else throw e;\n}","preventionTips":["Show an explainer UI before requesting notification permission to improve grant rates.","Wrap registration in try/catch so denial doesn't crash the app.","Remind users that iOS won't re-prompt after the first denial."],"tags":["expo-notifications","push-notifications","permissions","ios","android","notification-tester"],"backgroundTag":null,"analyzedSha":"b09195aac27c9e4a63daaf12dcb6f00b6b2e08ee","analyzedAt":"2026-08-12T15:59:58.304Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}