expo/expo · error · Error

Failed to get push token permission!

Error message

Failed to get push token permission!

What it means

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.

Source

Thrown at apps/notification-tester/src/registerForNotifications.ts:17

import Constants from 'expo-constants';
import {
  getExpoPushTokenAsync,
  getPermissionsAsync,
  requestPermissionsAsync,
} from 'expo-notifications';

export async function registerForPushNotificationsAsync() {
  const { status: existingStatus } = await getPermissionsAsync();
  let finalStatus = existingStatus;
  if (existingStatus !== 'granted') {
    const { status } = await requestPermissionsAsync();
    finalStatus = status;
  }
  if (finalStatus !== 'granted') {
    alert('Failed to get push token permission!');
    throw new Error('Failed to get push token permission!');
  }
  // Learn more about projectId:
  // https://docs.expo.dev/push-notifications/push-notifications-setup/#configure-projectid
  // Here we use EAS projectId
  const projectId = Constants?.expoConfig?.extra?.eas?.projectId ?? Constants?.easConfig?.projectId;
  if (!projectId) {
    throw new Error('Project ID not found');
  }
  const token = (
    await getExpoPushTokenAsync({
      projectId,
    })
  ).data;
  return token;
}

View on GitHub (pinned to b09195aac2)

Solutions

  1. Ask the user to enable notifications in OS Settings and re-launch, since iOS won't re-prompt after denial.
  2. Gate the registration call behind a UI that explains the value before requesting permission (improves grant rate).
  3. Wrap the call in try/catch so a denial degrades gracefully instead of crashing the app.

Example fix

// before
await registerForPushNotificationsAsync(); // throws on denial, crashes flow

// after
try {
  await registerForPushNotificationsAsync();
} catch (e) {
  Alert.alert('Notifications disabled', 'Enable them in Settings to receive alerts.');
}
Defensive patterns

Strategy: try-catch

Validate before calling

import { getPermissionsAsync } from 'expo-notifications';
async function hasNotificationPermission(): Promise<boolean> {
  const { status } = await getPermissionsAsync();
  return status === 'granted';
}

Try / catch

try {
  await registerForPushNotificationsAsync();
} catch (e) {
  if (/permission/i.test(e.message)) {
    Alert.alert('Notifications disabled', 'Enable them in Settings.');
  } else throw e;
}

Prevention

When it happens

Trigger: 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+).

Common situations: 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.

Related errors


AI-assisted analysis of expo/expo@b09195aac2 (2026-08-12). Data as JSON: /api/errors/c99f9de8bf8fedeb. Report an issue: GitHub.