Skip to main content

Troubleshooting

Common issues and solutions when using Superflag in React Native and Expo.

App Crashes in Production

Symptom

App works fine in development but crashes immediately on launch in TestFlight or production builds.

Solution

Quick checklist:
  1. Using public key (pub_*), not SDK key?
  2. AsyncStorage installed?
  3. Built with a production build locally?
# Test with production build
eas build --platform ios --profile preview

AsyncStorage Not Found

Symptom

Error: @RNC/AsyncStorage: NativeModule: AsyncStorage is null

Solution

Install AsyncStorage:
npx expo install @react-native-async-storage/async-storage
For bare React Native:
npm install @react-native-async-storage/async-storage
cd ios && pod install

Flags Not Loading

Symptom

useFlags() shows status: 'loading' forever, or status: 'error'.

Solution

Ensure you’re using a valid public client key (pub_*):
const { error } = useFlags()
console.log('Error:', error)  // Check what error is
Common issues:
  • Using wrong key (SDK key instead of public key)
  • Environment variable not set
  • Typo in key

Rate Limited

Symptom

status: 'rate-limited' or error message “Monthly quota exceeded”.

Solution

You’ve hit your plan’s monthly request limit. The SDK will continue using cached flags. To resolve:
  1. Increase cache TTL to reduce requests:
    <SuperflagProvider ttlSeconds={300}> {/* 5 minutes */}
    
  2. Upgrade your plan in the dashboard
  3. Check for request loops:
    // ❌ Don't do this - infinite loop
    useEffect(() => {
      client.refetch()  // Called on every render
    })
    
    // ✅ Do this - call only when needed
    const handleRefresh = () => {
      client.refetch()
    }
    

Slow Initial Load

Symptom

App shows loading state for several seconds on first launch.

Solution

This is expected on first launch. The SDK fetches flags and caches them. Subsequent launches are instant. To improve first launch:
  1. Show cached content while loading:
    const { ready } = useFlags()
    const feature = useFlag('feature', false)
    
    // Don't wait for ready - use cached/fallback values immediately
    return <View>{feature && <Feature />}</View>
    
  2. Preload flags before mounting:
    // app/_layout.tsx
    import { useFlags } from '@superflag-sh/react-native'
    import { SplashScreen } from 'expo-splash-screen'
    
    SplashScreen.preventAutoHideAsync()
    
    export default function Layout() {
      const { ready } = useFlags()
    
      useEffect(() => {
        if (ready) {
          SplashScreen.hideAsync()
        }
      }, [ready])
    
      return <Slot />
    }
    

TypeScript Errors

Symptom

TypeScript can’t find types or shows errors for SDK exports.

Solution

The SDK includes types out of the box. If you’re getting errors:
  1. Ensure you’re on TypeScript 5.0+:
    npm list typescript
    
  2. Add to tsconfig.json:
    {
      "compilerOptions": {
        "moduleResolution": "bundler",
        "skipLibCheck": true
      }
    }
    
  3. Restart TypeScript server in VS Code:
    • Cmd+Shift+P → “TypeScript: Restart TS Server”

Cache Not Persisting

Symptom

Flags reload from network every time app launches, even when cache should be valid.

Solution

Check AsyncStorage is working:
import AsyncStorage from '@react-native-async-storage/async-storage'

// Test AsyncStorage
AsyncStorage.setItem('test', 'value')
  .then(() => AsyncStorage.getItem('test'))
  .then(value => console.log('AsyncStorage works:', value === 'value'))
  .catch(err => console.error('AsyncStorage error:', err))
If AsyncStorage isn’t working:
  1. Reinstall: npx expo install @react-native-async-storage/async-storage
  2. For bare RN: cd ios && pod install
  3. Clear build cache: npx expo start --clear

Expo Updates ErrorRecovery Crash

Symptom

Crash log shows ErrorRecovery.notify or mentions expo-updates.

Solution

This means expo-updates detected an error during app startup and crashed to prevent a bad update from “bricking” your app.

Still Having Issues?

If none of these solutions work:
  1. Check the example app in the GitHub repo
  2. Enable debug logging:
    const { status, error, version } = useFlags()
    console.log('Status:', status)
    console.log('Error:', error)
    console.log('Version:', version)
    
  3. Test with a minimal reproduction:
    import { SuperflagProvider, useFlag } from '@superflag-sh/react-native'
    
    export default function App() {
      return (
        <SuperflagProvider clientKey="pub_...">
          <Test />
        </SuperflagProvider>
      )
    }
    
    function Test() {
      const flag = useFlag('test', false)
      return <Text>{String(flag)}</Text>
    }
    

Next Steps